testing_group.c 217 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324632563266327632863296330633163326333633463356336633763386339634063416342634363446345634663476348634963506351635263536354635563566357635863596360636163626363636463656366636763686369637063716372637363746375637663776378637963806381638263836384638563866387638863896390639163926393639463956396639763986399640064016402640364046405640664076408640964106411641264136414641564166417641864196420642164226423642464256426642764286429643064316432643364346435643664376438643964406441644264436444644564466447644864496450645164526453645464556456645764586459646064616462646364646465646664676468646964706471647264736474647564766477647864796480648164826483648464856486648764886489649064916492649364946495649664976498649965006501650265036504650565066507650865096510651165126513651465156516651765186519652065216522652365246525652665276528652965306531653265336534653565366537653865396540654165426543654465456546654765486549655065516552655365546555655665576558655965606561656265636564656565666567656865696570657165726573657465756576657765786579658065816582658365846585658665876588658965906591659265936594659565966597659865996600660166026603660466056606660766086609661066116612661366146615661666176618661966206621662266236624662566266627662866296630663166326633663466356636663766386639664066416642664366446645664666476648664966506651665266536654665566566657665866596660666166626663666466656666666766686669667066716672667366746675667666776678667966806681668266836684668566866687668866896690669166926693669466956696669766986699670067016702670367046705670667076708670967106711671267136714671567166717671867196720672167226723672467256726672767286729673067316732673367346735673667376738673967406741674267436744674567466747674867496750675167526753675467556756675767586759676067616762676367646765676667676768676967706771677267736774677567766777677867796780678167826783678467856786678767886789679067916792679367946795679667976798679968006801680268036804680568066807680868096810681168126813681468156816681768186819682068216822682368246825682668276828682968306831683268336834683568366837683868396840684168426843684468456846684768486849685068516852685368546855685668576858685968606861686268636864686568666867686868696870687168726873687468756876687768786879688068816882688368846885688668876888688968906891689268936894689568966897689868996900690169026903690469056906690769086909691069116912691369146915691669176918691969206921692269236924692569266927692869296930693169326933693469356936693769386939694069416942694369446945694669476948694969506951695269536954695569566957695869596960696169626963696469656966696769686969697069716972697369746975697669776978697969806981698269836984698569866987698869896990699169926993699469956996699769986999700070017002700370047005700670077008700970107011701270137014701570167017701870197020702170227023702470257026702770287029703070317032703370347035703670377038703970407041704270437044704570467047704870497050705170527053705470557056705770587059706070617062706370647065706670677068706970707071707270737074707570767077707870797080708170827083708470857086708770887089709070917092709370947095709670977098709971007101710271037104710571067107710871097110711171127113711471157116711771187119712071217122712371247125712671277128712971307131713271337134713571367137713871397140714171427143714471457146
  1. /*
  2. This file is part of GNUnet
  3. (C) 2008, 2009 Christian Grothoff (and other contributing authors)
  4. GNUnet is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published
  6. by the Free Software Foundation; either version 3, or (at your
  7. option) any later version.
  8. GNUnet is distributed in the hope that it will be useful, but
  9. WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with GNUnet; see the file COPYING. If not, write to the
  14. Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  15. Boston, MA 02111-1307, USA.
  16. */
  17. /**
  18. * @file testing/testing_group.c
  19. * @brief convenience API for writing testcases for GNUnet
  20. * @author Nathan Evans
  21. * @author Christian Grothoff
  22. *
  23. */
  24. #include "platform.h"
  25. #include "gnunet_constants.h"
  26. #include "gnunet_arm_service.h"
  27. #include "gnunet_testing_lib.h"
  28. #include "gnunet_core_service.h"
  29. #define VERBOSE_TESTING GNUNET_NO
  30. #define VERBOSE_TOPOLOGY GNUNET_NO
  31. #define DEBUG_CHURN GNUNET_NO
  32. #define USE_START_HELPER GNUNET_YES
  33. #define OLD 1
  34. /* Before connecting peers, send all of the HELLOs */
  35. #define USE_SEND_HELLOS GNUNET_NO
  36. #define TOPOLOGY_HACK GNUNET_YES
  37. /**
  38. * Lowest port used for GNUnet testing. Should be high enough to not
  39. * conflict with other applications running on the hosts but be low
  40. * enough to not conflict with client-ports (typically starting around
  41. * 32k).
  42. */
  43. #define LOW_PORT 12000
  44. /**
  45. * Highest port used for GNUnet testing. Should be low enough to not
  46. * conflict with the port range for "local" ports (client apps; see
  47. * /proc/sys/net/ipv4/ip_local_port_range on Linux for example).
  48. */
  49. #define HIGH_PORT 56000
  50. /* Maximum time to delay connect attempt */
  51. #define MAX_CONNECT_DELAY 300
  52. /**
  53. * Which list of peers do we need to modify?
  54. */
  55. enum PeerLists
  56. {
  57. /** Modify allowed peers */
  58. ALLOWED,
  59. /** Modify connect peers */
  60. CONNECT,
  61. /** Modify blacklist peers */
  62. BLACKLIST,
  63. /** Modify workingset peers */
  64. WORKING_SET
  65. };
  66. /**
  67. * Prototype of a function called whenever two peers would be connected
  68. * in a certain topology.
  69. */
  70. typedef unsigned int
  71. (*GNUNET_TESTING_ConnectionProcessor)(struct GNUNET_TESTING_PeerGroup * pg,
  72. unsigned int first, unsigned int second,
  73. enum PeerLists list, unsigned int check);
  74. /**
  75. * Context for handling churning a peer group
  76. */
  77. struct ChurnContext
  78. {
  79. /**
  80. * The peergroup we are dealing with.
  81. */
  82. struct GNUNET_TESTING_PeerGroup *pg;
  83. /**
  84. * Name of the service to churn on/off, NULL
  85. * to churn entire peer.
  86. */
  87. char *service;
  88. /**
  89. * Callback used to notify of churning finished
  90. */
  91. GNUNET_TESTING_NotifyCompletion cb;
  92. /**
  93. * Closure for callback
  94. */
  95. void *cb_cls;
  96. /**
  97. * Number of peers that still need to be started
  98. */
  99. unsigned int num_to_start;
  100. /**
  101. * Number of peers that still need to be stopped
  102. */
  103. unsigned int num_to_stop;
  104. /**
  105. * Number of peers that failed to start
  106. */
  107. unsigned int num_failed_start;
  108. /**
  109. * Number of peers that failed to stop
  110. */
  111. unsigned int num_failed_stop;
  112. };
  113. struct RestartContext
  114. {
  115. /**
  116. * The group of peers being restarted
  117. */
  118. struct GNUNET_TESTING_PeerGroup *peer_group;
  119. /**
  120. * How many peers have been restarted thus far
  121. */
  122. unsigned int peers_restarted;
  123. /**
  124. * How many peers got an error when restarting
  125. */
  126. unsigned int peers_restart_failed;
  127. /**
  128. * The function to call once all peers have been restarted
  129. */
  130. GNUNET_TESTING_NotifyCompletion callback;
  131. /**
  132. * Closure for callback function
  133. */
  134. void *callback_cls;
  135. };
  136. struct SendHelloContext
  137. {
  138. /**
  139. * Global handle to the peer group.
  140. */
  141. struct GNUNET_TESTING_PeerGroup *pg;
  142. /**
  143. * The data about this specific peer.
  144. */
  145. struct PeerData *peer;
  146. /**
  147. * The next HELLO that needs sent to this peer.
  148. */
  149. struct PeerConnection *peer_pos;
  150. /**
  151. * Are we connected to CORE yet?
  152. */
  153. unsigned int core_ready;
  154. /**
  155. * How many attempts should we make for failed connections?
  156. */
  157. unsigned int connect_attempts;
  158. /**
  159. * Task for scheduling core connect requests to be sent.
  160. */
  161. GNUNET_SCHEDULER_TaskIdentifier core_connect_task;
  162. };
  163. struct ShutdownContext
  164. {
  165. struct GNUNET_TESTING_PeerGroup *pg;
  166. /**
  167. * Total peers to wait for
  168. */
  169. unsigned int total_peers;
  170. /**
  171. * Number of peers successfully shut down
  172. */
  173. unsigned int peers_down;
  174. /**
  175. * Number of peers failed to shut down
  176. */
  177. unsigned int peers_failed;
  178. /**
  179. * Number of peers we have started shutting
  180. * down. If too many, wait on them.
  181. */
  182. unsigned int outstanding;
  183. /**
  184. * Timeout for shutdown.
  185. */
  186. struct GNUNET_TIME_Relative timeout;
  187. /**
  188. * Callback to call when all peers either
  189. * shutdown or failed to shutdown
  190. */
  191. GNUNET_TESTING_NotifyCompletion cb;
  192. /**
  193. * Closure for cb
  194. */
  195. void *cb_cls;
  196. /**
  197. * Should we delete all of the files from the peers?
  198. */
  199. int delete_files;
  200. };
  201. /**
  202. * Individual shutdown context for a particular peer.
  203. */
  204. struct PeerShutdownContext
  205. {
  206. /**
  207. * Pointer to the high level shutdown context.
  208. */
  209. struct ShutdownContext *shutdown_ctx;
  210. /**
  211. * The daemon handle for the peer to shut down.
  212. */
  213. struct GNUNET_TESTING_Daemon *daemon;
  214. };
  215. /**
  216. * Individual shutdown context for a particular peer.
  217. */
  218. struct PeerRestartContext
  219. {
  220. /**
  221. * Pointer to the high level restart context.
  222. */
  223. struct ChurnRestartContext *churn_restart_ctx;
  224. /**
  225. * The daemon handle for the peer to shut down.
  226. */
  227. struct GNUNET_TESTING_Daemon *daemon;
  228. };
  229. struct ServiceStartContext
  230. {
  231. struct GNUNET_TESTING_PeerGroup *pg;
  232. unsigned int remaining;
  233. GNUNET_TESTING_NotifyCompletion cb;
  234. unsigned int outstanding;
  235. char *service;
  236. struct GNUNET_TIME_Relative timeout;
  237. void *cb_cls;
  238. };
  239. /**
  240. * Individual shutdown context for a particular peer.
  241. */
  242. struct PeerServiceStartContext
  243. {
  244. /**
  245. * Pointer to the high level start context.
  246. */
  247. struct ServiceStartContext *start_ctx;
  248. /**
  249. * The daemon handle for the peer to start the service on.
  250. */
  251. struct GNUNET_TESTING_Daemon *daemon;
  252. };
  253. struct CreateTopologyContext
  254. {
  255. /**
  256. * Function to call with number of connections
  257. */
  258. GNUNET_TESTING_NotifyConnections cont;
  259. /**
  260. * Closure for connection notification
  261. */
  262. void *cls;
  263. };
  264. enum States
  265. {
  266. /** Waiting to read number of peers */
  267. NUM_PEERS,
  268. /** Should find next peer index */
  269. PEER_INDEX,
  270. /** Should find colon */
  271. COLON,
  272. /** Should read other peer index, space, or endline */
  273. OTHER_PEER_INDEX
  274. };
  275. #if OLD
  276. struct PeerConnection
  277. {
  278. /**
  279. * Doubly Linked list
  280. */
  281. struct PeerConnection *prev;
  282. /*
  283. * Doubly Linked list
  284. */
  285. struct PeerConnection *next;
  286. /*
  287. * Index of daemon in pg->peers
  288. */
  289. uint32_t index;
  290. };
  291. #endif
  292. struct InternalStartContext
  293. {
  294. /**
  295. * Pointer to peerdata
  296. */
  297. struct PeerData *peer;
  298. /**
  299. * Timeout for peer startup
  300. */
  301. struct GNUNET_TIME_Relative timeout;
  302. /**
  303. * Client callback for hostkey notification
  304. */
  305. GNUNET_TESTING_NotifyHostkeyCreated hostkey_callback;
  306. /**
  307. * Closure for hostkey_callback
  308. */
  309. void *hostkey_cls;
  310. /**
  311. * Client callback for peer start notification
  312. */
  313. GNUNET_TESTING_NotifyDaemonRunning start_cb;
  314. /**
  315. * Closure for cb
  316. */
  317. void *start_cb_cls;
  318. /**
  319. * Hostname, where to start the peer
  320. */
  321. const char *hostname;
  322. /**
  323. * Username to use when connecting to the
  324. * host via ssh.
  325. */
  326. const char *username;
  327. /**
  328. * Pointer to starting memory location of a hostkey
  329. */
  330. const char *hostkey;
  331. /**
  332. * Port to use for ssh.
  333. */
  334. uint16_t sshport;
  335. };
  336. struct ChurnRestartContext
  337. {
  338. /**
  339. * PeerGroup that we are working with.
  340. */
  341. struct GNUNET_TESTING_PeerGroup *pg;
  342. /**
  343. * Number of restarts currently in flight.
  344. */
  345. unsigned int outstanding;
  346. /**
  347. * Handle to the underlying churn context.
  348. */
  349. struct ChurnContext *churn_ctx;
  350. /**
  351. * How long to allow the operation to take.
  352. */
  353. struct GNUNET_TIME_Relative timeout;
  354. };
  355. struct OutstandingSSH
  356. {
  357. struct OutstandingSSH *next;
  358. struct OutstandingSSH *prev;
  359. /**
  360. * Number of current ssh connections.
  361. */
  362. uint32_t outstanding;
  363. /**
  364. * The hostname of this peer.
  365. */
  366. const char *hostname;
  367. };
  368. /**
  369. * Data we keep per peer.
  370. */
  371. struct PeerData
  372. {
  373. /**
  374. * (Initial) configuration of the host.
  375. * (initial because clients could change
  376. * it and we would not know about those
  377. * updates).
  378. */
  379. struct GNUNET_CONFIGURATION_Handle *cfg;
  380. /**
  381. * Handle for controlling the daemon.
  382. */
  383. struct GNUNET_TESTING_Daemon *daemon;
  384. /**
  385. * The peergroup this peer belongs to.
  386. */
  387. struct GNUNET_TESTING_PeerGroup *pg;
  388. #if OLD
  389. /**
  390. * Linked list of allowed peer connections.
  391. */
  392. struct PeerConnection *allowed_peers_head;
  393. /**
  394. * Linked list of allowed peer connections.
  395. */
  396. struct PeerConnection *allowed_peers_tail;
  397. /**
  398. * Linked list of blacklisted peer connections.
  399. */
  400. struct PeerConnection *blacklisted_peers_head;
  401. /**
  402. * Linked list of blacklisted peer connections.
  403. */
  404. struct PeerConnection *blacklisted_peers_tail;
  405. /**
  406. * Linked list of connect peer connections.
  407. */
  408. struct PeerConnection *connect_peers_head;
  409. /**
  410. * Linked list of connect peer connections.
  411. */
  412. struct PeerConnection *connect_peers_tail;
  413. /**
  414. * Linked list of connect peer connections.
  415. */
  416. struct PeerConnection *connect_peers_working_set_head;
  417. /**
  418. * Linked list of connect peer connections.
  419. */
  420. struct PeerConnection *connect_peers_working_set_tail;
  421. #else
  422. /**
  423. * Hash map of allowed peer connections (F2F created topology)
  424. */
  425. struct GNUNET_CONTAINER_MultiHashMap *allowed_peers;
  426. /**
  427. * Hash map of blacklisted peers
  428. */
  429. struct GNUNET_CONTAINER_MultiHashMap *blacklisted_peers;
  430. /**
  431. * Hash map of peer connections
  432. */
  433. struct GNUNET_CONTAINER_MultiHashMap *connect_peers;
  434. /**
  435. * Temporary hash map of peer connections
  436. */
  437. struct GNUNET_CONTAINER_MultiHashMap *connect_peers_working_set;
  438. #endif
  439. /**
  440. * Temporary variable for topology creation, should be reset before
  441. * creating any topology so the count is valid once finished.
  442. */
  443. int num_connections;
  444. /**
  445. * Context to keep track of peers being started, to
  446. * stagger hostkey generation and peer startup.
  447. */
  448. struct InternalStartContext internal_context;
  449. };
  450. /**
  451. * Linked list of per-host data.
  452. */
  453. struct HostData
  454. {
  455. /**
  456. * Name of the host.
  457. */
  458. char *hostname;
  459. /**
  460. * SSH username to use when connecting to this host.
  461. */
  462. char *username;
  463. /**
  464. * SSH port to use when connecting to this host.
  465. */
  466. uint16_t sshport;
  467. /**
  468. * Lowest port that we have not yet used
  469. * for GNUnet.
  470. */
  471. uint16_t minport;
  472. };
  473. struct TopologyIterateContext
  474. {
  475. /**
  476. * The peergroup we are working with.
  477. */
  478. struct GNUNET_TESTING_PeerGroup *pg;
  479. /**
  480. * Callback for notifying of two connected peers.
  481. */
  482. GNUNET_TESTING_NotifyTopology topology_cb;
  483. /**
  484. * Closure for topology_cb
  485. */
  486. void *cls;
  487. /**
  488. * Number of peers currently connected to.
  489. */
  490. unsigned int connected;
  491. /**
  492. * Number of peers we have finished iterating.
  493. */
  494. unsigned int completed;
  495. /**
  496. * Number of peers total.
  497. */
  498. unsigned int total;
  499. };
  500. struct StatsIterateContext
  501. {
  502. /**
  503. * The peergroup that we are dealing with.
  504. */
  505. struct GNUNET_TESTING_PeerGroup *pg;
  506. /**
  507. * Continuation to call once all stats information has been retrieved.
  508. */
  509. GNUNET_STATISTICS_Callback cont;
  510. /**
  511. * Proc function to call on each value received.
  512. */
  513. GNUNET_TESTING_STATISTICS_Iterator proc;
  514. /**
  515. * Closure for topology_cb
  516. */
  517. void *cls;
  518. /**
  519. * Number of peers currently connected to.
  520. */
  521. unsigned int connected;
  522. /**
  523. * Number of peers we have finished iterating.
  524. */
  525. unsigned int completed;
  526. /**
  527. * Number of peers total.
  528. */
  529. unsigned int total;
  530. };
  531. struct CoreContext
  532. {
  533. void *iter_context;
  534. struct GNUNET_TESTING_Daemon *daemon;
  535. };
  536. struct StatsCoreContext
  537. {
  538. void *iter_context;
  539. struct GNUNET_TESTING_Daemon *daemon;
  540. /**
  541. * Handle to the statistics service.
  542. */
  543. struct GNUNET_STATISTICS_Handle *stats_handle;
  544. /**
  545. * Handle for getting statistics.
  546. */
  547. struct GNUNET_STATISTICS_GetHandle *stats_get_handle;
  548. };
  549. struct ConnectTopologyContext
  550. {
  551. /**
  552. * How many connections are left to create.
  553. */
  554. unsigned int remaining_connections;
  555. /**
  556. * Handle to group of peers.
  557. */
  558. struct GNUNET_TESTING_PeerGroup *pg;
  559. /**
  560. * How long to try this connection before timing out.
  561. */
  562. struct GNUNET_TIME_Relative connect_timeout;
  563. /**
  564. * How many times to retry connecting the two peers.
  565. */
  566. unsigned int connect_attempts;
  567. /**
  568. * Temp value set for each iteration.
  569. */
  570. //struct PeerData *first;
  571. /**
  572. * Notification that all peers are connected.
  573. */
  574. GNUNET_TESTING_NotifyCompletion notify_connections_done;
  575. /**
  576. * Closure for notify.
  577. */
  578. void *notify_cls;
  579. };
  580. /**
  581. * Handle to a group of GNUnet peers.
  582. */
  583. struct GNUNET_TESTING_PeerGroup
  584. {
  585. /**
  586. * Configuration template.
  587. */
  588. const struct GNUNET_CONFIGURATION_Handle *cfg;
  589. /**
  590. * Function to call on each started daemon.
  591. */
  592. //GNUNET_TESTING_NotifyDaemonRunning cb;
  593. /**
  594. * Closure for cb.
  595. */
  596. //void *cb_cls;
  597. /*
  598. * Function to call on each topology connection created
  599. */
  600. GNUNET_TESTING_NotifyConnection notify_connection;
  601. /*
  602. * Callback for notify_connection
  603. */
  604. void *notify_connection_cls;
  605. /**
  606. * Array of information about hosts.
  607. */
  608. struct HostData *hosts;
  609. /**
  610. * Number of hosts (size of HostData)
  611. */
  612. unsigned int num_hosts;
  613. /**
  614. * Array of "total" peers.
  615. */
  616. struct PeerData *peers;
  617. /**
  618. * Number of peers in this group.
  619. */
  620. unsigned int total;
  621. /**
  622. * At what time should we fail the peer startup process?
  623. */
  624. struct GNUNET_TIME_Absolute max_timeout;
  625. /**
  626. * How many peers are being started right now?
  627. */
  628. unsigned int starting;
  629. /**
  630. * How many peers have already been started?
  631. */
  632. unsigned int started;
  633. /**
  634. * Number of possible connections to peers
  635. * at a time.
  636. */
  637. unsigned int max_outstanding_connections;
  638. /**
  639. * Number of ssh connections to peers (max).
  640. */
  641. unsigned int max_concurrent_ssh;
  642. /**
  643. * Number of connects we are waiting on, allows us to rate limit
  644. * connect attempts.
  645. */
  646. unsigned int outstanding_connects;
  647. /**
  648. * Number of HELLOs we have yet to send.
  649. */
  650. unsigned int remaining_hellos;
  651. /**
  652. * How many connects have already been scheduled?
  653. */
  654. unsigned int total_connects_scheduled;
  655. /**
  656. * Hostkeys loaded from a file.
  657. */
  658. char *hostkey_data;
  659. /**
  660. * Head of DLL to keep track of the number of outstanding
  661. * ssh connections per peer.
  662. */
  663. struct OutstandingSSH *ssh_head;
  664. /**
  665. * Tail of DLL to keep track of the number of outstanding
  666. * ssh connections per peer.
  667. */
  668. struct OutstandingSSH *ssh_tail;
  669. /**
  670. * Stop scheduling peers connecting.
  671. */
  672. unsigned int stop_connects;
  673. /**
  674. * Connection context for peer group.
  675. */
  676. struct ConnectTopologyContext ct_ctx;
  677. };
  678. struct UpdateContext
  679. {
  680. /**
  681. * The altered configuration.
  682. */
  683. struct GNUNET_CONFIGURATION_Handle *ret;
  684. /**
  685. * The original configuration to alter.
  686. */
  687. const struct GNUNET_CONFIGURATION_Handle *orig;
  688. /**
  689. * The hostname that this peer will run on.
  690. */
  691. const char *hostname;
  692. /**
  693. * The next possible port to assign.
  694. */
  695. unsigned int nport;
  696. /**
  697. * Unique number for unix domain sockets.
  698. */
  699. unsigned int upnum;
  700. /**
  701. * Unique number for this peer/host to offset
  702. * things that are grouped by host.
  703. */
  704. unsigned int fdnum;
  705. };
  706. struct ConnectContext
  707. {
  708. /**
  709. * Index of peer to connect second to.
  710. */
  711. uint32_t first_index;
  712. /**
  713. * Index of peer to connect first to.
  714. */
  715. uint32_t second_index;
  716. /**
  717. * Higher level topology connection context.
  718. */
  719. struct ConnectTopologyContext *ct_ctx;
  720. /**
  721. * Whether this connection has been accounted for in the schedule_connect call.
  722. */
  723. int counted;
  724. };
  725. struct UnblacklistContext
  726. {
  727. /**
  728. * The peergroup
  729. */
  730. struct GNUNET_TESTING_PeerGroup *pg;
  731. /**
  732. * uid of the first peer
  733. */
  734. uint32_t first_uid;
  735. };
  736. struct RandomContext
  737. {
  738. /**
  739. * The peergroup
  740. */
  741. struct GNUNET_TESTING_PeerGroup *pg;
  742. /**
  743. * uid of the first peer
  744. */
  745. uint32_t first_uid;
  746. /**
  747. * Peer data for first peer.
  748. */
  749. struct PeerData *first;
  750. /**
  751. * Random percentage to use
  752. */
  753. double percentage;
  754. };
  755. struct MinimumContext
  756. {
  757. /**
  758. * The peergroup
  759. */
  760. struct GNUNET_TESTING_PeerGroup *pg;
  761. /**
  762. * uid of the first peer
  763. */
  764. uint32_t first_uid;
  765. /**
  766. * Peer data for first peer.
  767. */
  768. struct PeerData *first;
  769. /**
  770. * Number of conns per peer
  771. */
  772. unsigned int num_to_add;
  773. /**
  774. * Permuted array of all possible connections. Only add the Nth
  775. * peer if it's in the Nth position.
  776. */
  777. unsigned int *pg_array;
  778. /**
  779. * What number is the current element we are iterating over?
  780. */
  781. unsigned int current;
  782. };
  783. struct DFSContext
  784. {
  785. /**
  786. * The peergroup
  787. */
  788. struct GNUNET_TESTING_PeerGroup *pg;
  789. /**
  790. * uid of the first peer
  791. */
  792. uint32_t first_uid;
  793. /**
  794. * uid of the second peer
  795. */
  796. uint32_t second_uid;
  797. /**
  798. * Peer data for first peer.
  799. */
  800. struct PeerData *first;
  801. /**
  802. * Which peer has been chosen as the one to add?
  803. */
  804. unsigned int chosen;
  805. /**
  806. * What number is the current element we are iterating over?
  807. */
  808. unsigned int current;
  809. };
  810. /**
  811. * Simple struct to keep track of progress, and print a
  812. * nice little percentage meter for long running tasks.
  813. */
  814. struct ProgressMeter
  815. {
  816. unsigned int total;
  817. unsigned int modnum;
  818. unsigned int dotnum;
  819. unsigned int completed;
  820. int print;
  821. char *startup_string;
  822. };
  823. #if !OLD
  824. /**
  825. * Convert unique ID to hash code.
  826. *
  827. * @param uid unique ID to convert
  828. * @param hash set to uid (extended with zeros)
  829. */
  830. static void
  831. hash_from_uid (uint32_t uid, GNUNET_HashCode * hash)
  832. {
  833. memset (hash, 0, sizeof (GNUNET_HashCode));
  834. *((uint32_t *) hash) = uid;
  835. }
  836. /**
  837. * Convert hash code to unique ID.
  838. *
  839. * @param uid unique ID to convert
  840. * @param hash set to uid (extended with zeros)
  841. */
  842. static void
  843. uid_from_hash (const GNUNET_HashCode * hash, uint32_t * uid)
  844. {
  845. memcpy (uid, hash, sizeof (uint32_t));
  846. }
  847. #endif
  848. #if USE_SEND_HELLOS
  849. static struct GNUNET_CORE_MessageHandler no_handlers[] =
  850. {
  851. { NULL, 0, 0}};
  852. #endif
  853. /**
  854. * Create a meter to keep track of the progress of some task.
  855. *
  856. * @param total the total number of items to complete
  857. * @param start_string a string to prefix the meter with (if printing)
  858. * @param print GNUNET_YES to print the meter, GNUNET_NO to count
  859. * internally only
  860. *
  861. * @return the progress meter
  862. */
  863. static struct ProgressMeter *
  864. create_meter(unsigned int total, char * start_string, int print)
  865. {
  866. struct ProgressMeter *ret;
  867. ret = GNUNET_malloc(sizeof(struct ProgressMeter));
  868. ret->print = print;
  869. ret->total = total;
  870. ret->modnum = total / 4;
  871. if (ret->modnum == 0) /* Divide by zero check */
  872. ret->modnum = 1;
  873. ret->dotnum = (total / 50) + 1;
  874. if (start_string != NULL)
  875. ret->startup_string = GNUNET_strdup(start_string);
  876. else
  877. ret->startup_string = GNUNET_strdup("");
  878. return ret;
  879. }
  880. /**
  881. * Update progress meter (increment by one).
  882. *
  883. * @param meter the meter to update and print info for
  884. *
  885. * @return GNUNET_YES if called the total requested,
  886. * GNUNET_NO if more items expected
  887. */
  888. static int
  889. update_meter(struct ProgressMeter *meter)
  890. {
  891. if (meter->print == GNUNET_YES)
  892. {
  893. if (meter->completed % meter->modnum == 0)
  894. {
  895. if (meter->completed == 0)
  896. {
  897. fprintf (stdout, "%sProgress: [0%%", meter->startup_string);
  898. }
  899. else
  900. fprintf (stdout, "%d%%", (int) (((float) meter->completed
  901. / meter->total) * 100));
  902. }
  903. else if (meter->completed % meter->dotnum == 0)
  904. fprintf (stdout, ".");
  905. if (meter->completed + 1 == meter->total)
  906. fprintf (stdout, "%d%%]\n", 100);
  907. fflush (stdout);
  908. }
  909. meter->completed++;
  910. if (meter->completed == meter->total)
  911. return GNUNET_YES;
  912. if (meter->completed > meter->total)
  913. GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Progress meter overflow!!\n");
  914. return GNUNET_NO;
  915. }
  916. /**
  917. * Reset progress meter.
  918. *
  919. * @param meter the meter to reset
  920. *
  921. * @return GNUNET_YES if meter reset,
  922. * GNUNET_SYSERR on error
  923. */
  924. static int
  925. reset_meter(struct ProgressMeter *meter)
  926. {
  927. if (meter == NULL)
  928. return GNUNET_SYSERR;
  929. meter->completed = 0;
  930. return GNUNET_YES;
  931. }
  932. /**
  933. * Release resources for meter
  934. *
  935. * @param meter the meter to free
  936. */
  937. static void
  938. free_meter(struct ProgressMeter *meter)
  939. {
  940. GNUNET_free_non_null (meter->startup_string);
  941. GNUNET_free (meter);
  942. }
  943. /**
  944. * Get a topology from a string input.
  945. *
  946. * @param topology where to write the retrieved topology
  947. * @param topology_string The string to attempt to
  948. * get a configuration value from
  949. * @return GNUNET_YES if topology string matched a
  950. * known topology, GNUNET_NO if not
  951. */
  952. int
  953. GNUNET_TESTING_topology_get(enum GNUNET_TESTING_Topology *topology,
  954. const char *topology_string)
  955. {
  956. /**
  957. * Strings representing topologies in enum
  958. */
  959. static const char *topology_strings[] =
  960. {
  961. /**
  962. * A clique (everyone connected to everyone else).
  963. */
  964. "CLIQUE",
  965. /**
  966. * Small-world network (2d torus plus random links).
  967. */
  968. "SMALL_WORLD",
  969. /**
  970. * Small-world network (ring plus random links).
  971. */
  972. "SMALL_WORLD_RING",
  973. /**
  974. * Ring topology.
  975. */
  976. "RING",
  977. /**
  978. * 2-d torus.
  979. */
  980. "2D_TORUS",
  981. /**
  982. * Random graph.
  983. */
  984. "ERDOS_RENYI",
  985. /**
  986. * Certain percentage of peers are unable to communicate directly
  987. * replicating NAT conditions
  988. */
  989. "INTERNAT",
  990. /**
  991. * Scale free topology.
  992. */
  993. "SCALE_FREE",
  994. /**
  995. * Straight line topology.
  996. */
  997. "LINE",
  998. /**
  999. * All peers are disconnected.
  1000. */
  1001. "NONE",
  1002. /**
  1003. * Read the topology from a file.
  1004. */
  1005. "FROM_FILE",
  1006. NULL };
  1007. int curr = 0;
  1008. if (topology_string == NULL)
  1009. return GNUNET_NO;
  1010. while (topology_strings[curr] != NULL)
  1011. {
  1012. if (strcasecmp (topology_strings[curr], topology_string) == 0)
  1013. {
  1014. *topology = curr;
  1015. return GNUNET_YES;
  1016. }
  1017. curr++;
  1018. }
  1019. *topology = GNUNET_TESTING_TOPOLOGY_NONE;
  1020. return GNUNET_NO;
  1021. }
  1022. /**
  1023. * Get connect topology option from string input.
  1024. *
  1025. * @param topology_option where to write the retrieved topology
  1026. * @param topology_string The string to attempt to
  1027. * get a configuration value from
  1028. * @return GNUNET_YES if string matched a known
  1029. * topology option, GNUNET_NO if not
  1030. */
  1031. int
  1032. GNUNET_TESTING_topology_option_get(
  1033. enum GNUNET_TESTING_TopologyOption *topology_option,
  1034. const char *topology_string)
  1035. {
  1036. /**
  1037. * Options for connecting a topology as strings.
  1038. */
  1039. static const char *topology_option_strings[] =
  1040. {
  1041. /**
  1042. * Try to connect all peers specified in the topology.
  1043. */
  1044. "CONNECT_ALL",
  1045. /**
  1046. * Choose a random subset of connections to create.
  1047. */
  1048. "CONNECT_RANDOM_SUBSET",
  1049. /**
  1050. * Create at least X connections for each peer.
  1051. */
  1052. "CONNECT_MINIMUM",
  1053. /**
  1054. * Using a depth first search, create one connection
  1055. * per peer. If any are missed (graph disconnected)
  1056. * start over at those peers until all have at least one
  1057. * connection.
  1058. */
  1059. "CONNECT_DFS",
  1060. /**
  1061. * Find the N closest peers to each allowed peer in the
  1062. * topology and make sure a connection to those peers
  1063. * exists in the connect topology.
  1064. */
  1065. "CONNECT_CLOSEST",
  1066. /**
  1067. * No options specified.
  1068. */
  1069. "CONNECT_NONE",
  1070. NULL };
  1071. int curr = 0;
  1072. if (topology_string == NULL)
  1073. return GNUNET_NO;
  1074. while (NULL != topology_option_strings[curr])
  1075. {
  1076. if (strcasecmp (topology_option_strings[curr], topology_string) == 0)
  1077. {
  1078. *topology_option = curr;
  1079. return GNUNET_YES;
  1080. }
  1081. curr++;
  1082. }
  1083. *topology_option = GNUNET_TESTING_TOPOLOGY_OPTION_NONE;
  1084. return GNUNET_NO;
  1085. }
  1086. /**
  1087. * Function to iterate over options. Copies
  1088. * the options to the target configuration,
  1089. * updating PORT values as needed.
  1090. *
  1091. * @param cls closure
  1092. * @param section name of the section
  1093. * @param option name of the option
  1094. * @param value value of the option
  1095. */
  1096. static void
  1097. update_config(void *cls, const char *section, const char *option,
  1098. const char *value)
  1099. {
  1100. struct UpdateContext *ctx = cls;
  1101. unsigned int ival;
  1102. char cval[12];
  1103. char uval[128];
  1104. char *single_variable;
  1105. char *per_host_variable;
  1106. unsigned long long num_per_host;
  1107. GNUNET_asprintf (&single_variable, "single_%s_per_host", section);
  1108. GNUNET_asprintf (&per_host_variable, "num_%s_per_host", section);
  1109. if ((0 == strcmp (option, "PORT")) && (1 == sscanf (value, "%u", &ival)))
  1110. {
  1111. if ((ival != 0) && (GNUNET_YES
  1112. != GNUNET_CONFIGURATION_get_value_yesno (ctx->orig, "testing",
  1113. single_variable)))
  1114. {
  1115. GNUNET_snprintf (cval, sizeof(cval), "%u", ctx->nport++);
  1116. value = cval;
  1117. }
  1118. else if ((ival != 0) && (GNUNET_YES
  1119. == GNUNET_CONFIGURATION_get_value_yesno (ctx->orig, "testing",
  1120. single_variable))
  1121. && GNUNET_CONFIGURATION_get_value_number (ctx->orig, "testing",
  1122. per_host_variable,
  1123. &num_per_host))
  1124. {
  1125. GNUNET_snprintf (cval, sizeof(cval), "%u", ival + ctx->fdnum
  1126. % num_per_host);
  1127. value = cval;
  1128. }
  1129. /* FIXME: REMOVE FOREVER HACK HACK HACK */
  1130. if (0 == strcasecmp (section, "transport-tcp"))
  1131. GNUNET_CONFIGURATION_set_value_string (ctx->ret, section, "ADVERTISED_PORT", value);
  1132. }
  1133. if (0 == strcmp (option, "UNIXPATH"))
  1134. {
  1135. if (GNUNET_YES != GNUNET_CONFIGURATION_get_value_yesno (ctx->orig,
  1136. "testing",
  1137. single_variable))
  1138. {
  1139. GNUNET_snprintf (uval, sizeof(uval), "/tmp/test-service-%s-%u",
  1140. section, ctx->upnum++);
  1141. value = uval;
  1142. }
  1143. else if ((GNUNET_YES
  1144. == GNUNET_CONFIGURATION_get_value_number (ctx->orig, "testing",
  1145. per_host_variable,
  1146. &num_per_host))
  1147. && (num_per_host > 0))
  1148. {
  1149. GNUNET_snprintf (uval, sizeof(uval), "/tmp/test-service-%s-%u",
  1150. section, ctx->fdnum % num_per_host);
  1151. value = uval;
  1152. }
  1153. }
  1154. if ((0 == strcmp (option, "HOSTNAME")) && (ctx->hostname != NULL))
  1155. {
  1156. value = ctx->hostname;
  1157. }
  1158. GNUNET_free (single_variable);
  1159. GNUNET_free (per_host_variable);
  1160. GNUNET_CONFIGURATION_set_value_string (ctx->ret, section, option, value);
  1161. }
  1162. /**
  1163. * Create a new configuration using the given configuration
  1164. * as a template; however, each PORT in the existing cfg
  1165. * must be renumbered by incrementing "*port". If we run
  1166. * out of "*port" numbers, return NULL.
  1167. *
  1168. * @param cfg template configuration
  1169. * @param off the current peer offset
  1170. * @param port port numbers to use, update to reflect
  1171. * port numbers that were used
  1172. * @param upnum number to make unix domain socket names unique
  1173. * @param hostname hostname of the controlling host, to allow control connections from
  1174. * @param fdnum number used to offset the unix domain socket for grouped processes
  1175. * (such as statistics or peerinfo, which can be shared among others)
  1176. *
  1177. * @return new configuration, NULL on error
  1178. */
  1179. static struct GNUNET_CONFIGURATION_Handle *
  1180. make_config(const struct GNUNET_CONFIGURATION_Handle *cfg, uint32_t off,
  1181. uint16_t * port, uint32_t * upnum, const char *hostname,
  1182. uint32_t * fdnum)
  1183. {
  1184. struct UpdateContext uc;
  1185. uint16_t orig;
  1186. char *control_host;
  1187. char *allowed_hosts;
  1188. unsigned long long skew_variance;
  1189. unsigned long long skew_offset;
  1190. long long actual_offset;
  1191. orig = *port;
  1192. uc.nport = *port;
  1193. uc.upnum = *upnum;
  1194. uc.fdnum = *fdnum;
  1195. uc.ret = GNUNET_CONFIGURATION_create ();
  1196. uc.hostname = hostname;
  1197. uc.orig = cfg;
  1198. GNUNET_CONFIGURATION_iterate (cfg, &update_config, &uc);
  1199. if (uc.nport >= HIGH_PORT)
  1200. {
  1201. *port = orig;
  1202. GNUNET_CONFIGURATION_destroy (uc.ret);
  1203. return NULL;
  1204. }
  1205. if ((GNUNET_OK == GNUNET_CONFIGURATION_get_value_number (cfg, "testing",
  1206. "skew_variance",
  1207. &skew_variance))
  1208. && (skew_variance > 0))
  1209. {
  1210. skew_offset = GNUNET_CRYPTO_random_u64(GNUNET_CRYPTO_QUALITY_WEAK, skew_variance + 1);
  1211. actual_offset = skew_offset - GNUNET_CRYPTO_random_u64(GNUNET_CRYPTO_QUALITY_WEAK, skew_variance + 1);
  1212. /* Min is -skew_variance, Max is skew_variance */
  1213. skew_offset = skew_variance + actual_offset; /* Normal distribution around 0 */
  1214. GNUNET_CONFIGURATION_set_value_number(uc.ret, "testing", "skew_offset", skew_offset);
  1215. }
  1216. if (GNUNET_CONFIGURATION_get_value_string (cfg, "testing", "control_host",
  1217. &control_host) == GNUNET_OK)
  1218. {
  1219. if (hostname != NULL)
  1220. GNUNET_asprintf (&allowed_hosts, "%s; 127.0.0.1; %s;", control_host,
  1221. hostname);
  1222. else
  1223. GNUNET_asprintf (&allowed_hosts, "%s; 127.0.0.1;", control_host);
  1224. GNUNET_CONFIGURATION_set_value_string (uc.ret, "core", "ACCEPT_FROM",
  1225. allowed_hosts);
  1226. GNUNET_CONFIGURATION_set_value_string (uc.ret, "nse", "ACCEPT_FROM",
  1227. allowed_hosts);
  1228. GNUNET_CONFIGURATION_set_value_string (uc.ret, "transport",
  1229. "ACCEPT_FROM", allowed_hosts);
  1230. GNUNET_CONFIGURATION_set_value_string (uc.ret, "dht", "ACCEPT_FROM",
  1231. allowed_hosts);
  1232. GNUNET_CONFIGURATION_set_value_string (uc.ret, "statistics",
  1233. "ACCEPT_FROM", allowed_hosts);
  1234. GNUNET_CONFIGURATION_set_value_string (uc.ret, "core", "UNIXPATH", "");
  1235. GNUNET_CONFIGURATION_set_value_string (uc.ret, "transport", "UNIXPATH",
  1236. "");
  1237. GNUNET_CONFIGURATION_set_value_string (uc.ret, "dht", "UNIXPATH", "");
  1238. GNUNET_CONFIGURATION_set_value_string (uc.ret, "statistics", "UNIXPATH",
  1239. "");
  1240. GNUNET_CONFIGURATION_set_value_string (uc.ret, "nse", "UNIXPATH", "");
  1241. GNUNET_CONFIGURATION_set_value_string (uc.ret, "transport-tcp", "USE_LOCALADDR",
  1242. "YES");
  1243. GNUNET_CONFIGURATION_set_value_string (uc.ret, "transport-udp", "USE_LOCALADDR",
  1244. "YES");
  1245. GNUNET_free_non_null (control_host);
  1246. GNUNET_free (allowed_hosts);
  1247. }
  1248. /* arm needs to know to allow connections from the host on which it is running,
  1249. * otherwise gnunet-arm is unable to connect to it in some instances */
  1250. if (hostname != NULL)
  1251. {
  1252. GNUNET_asprintf (&allowed_hosts, "%s; 127.0.0.1;", hostname);
  1253. GNUNET_CONFIGURATION_set_value_string (uc.ret, "nat", "BINDTO",
  1254. hostname);
  1255. GNUNET_CONFIGURATION_set_value_string (uc.ret, "nat", "INTERNAL_ADDRESS",
  1256. hostname);
  1257. GNUNET_CONFIGURATION_set_value_string (uc.ret, "nat", "EXTERNAL_ADDRESS",
  1258. hostname);
  1259. GNUNET_CONFIGURATION_set_value_string (uc.ret, "disablev6", "BINDTO",
  1260. "YES");
  1261. GNUNET_CONFIGURATION_set_value_string (uc.ret, "transport-tcp", "USE_LOCALADDR",
  1262. "YES");
  1263. GNUNET_CONFIGURATION_set_value_string (uc.ret, "transport-udp", "USE_LOCALADDR",
  1264. "YES");
  1265. GNUNET_CONFIGURATION_set_value_string (uc.ret, "arm", "ACCEPT_FROM",
  1266. allowed_hosts);
  1267. GNUNET_free (allowed_hosts);
  1268. }
  1269. else
  1270. {
  1271. GNUNET_CONFIGURATION_set_value_string (uc.ret, "transport-tcp", "USE_LOCALADDR",
  1272. "YES");
  1273. GNUNET_CONFIGURATION_set_value_string (uc.ret, "transport-udp", "USE_LOCALADDR",
  1274. "YES");
  1275. GNUNET_CONFIGURATION_set_value_string (uc.ret, "nat", "BINDTO",
  1276. "127.0.0.1");
  1277. GNUNET_CONFIGURATION_set_value_string (uc.ret, "nat", "INTERNAL_ADDRESS",
  1278. "127.0.0.1");
  1279. GNUNET_CONFIGURATION_set_value_string (uc.ret, "nat", "EXTERNAL_ADDRESS",
  1280. "127.0.0.1");
  1281. GNUNET_CONFIGURATION_set_value_string (uc.ret, "disablev6", "BINDTO",
  1282. "YES");
  1283. }
  1284. *port = (uint16_t) uc.nport;
  1285. *upnum = uc.upnum;
  1286. uc.fdnum++;
  1287. *fdnum = uc.fdnum;
  1288. return uc.ret;
  1289. }
  1290. /*
  1291. * Remove entries from the peer connection list
  1292. *
  1293. * @param pg the peer group we are working with
  1294. * @param first index of the first peer
  1295. * @param second index of the second peer
  1296. * @param list the peer list to use
  1297. * @param check UNUSED
  1298. *
  1299. * @return the number of connections added (can be 0, 1 or 2)
  1300. *
  1301. */
  1302. static unsigned int
  1303. remove_connections(struct GNUNET_TESTING_PeerGroup *pg, unsigned int first,
  1304. unsigned int second, enum PeerLists list, unsigned int check)
  1305. {
  1306. int removed;
  1307. #if OLD
  1308. struct PeerConnection **first_list;
  1309. struct PeerConnection **second_list;
  1310. struct PeerConnection *first_iter;
  1311. struct PeerConnection *second_iter;
  1312. struct PeerConnection **first_tail;
  1313. struct PeerConnection **second_tail;
  1314. #else
  1315. GNUNET_HashCode hash_first;
  1316. GNUNET_HashCode hash_second;
  1317. hash_from_uid (first, &hash_first);
  1318. hash_from_uid (second, &hash_second);
  1319. #endif
  1320. removed = 0;
  1321. #if OLD
  1322. switch (list)
  1323. {
  1324. case ALLOWED:
  1325. first_list = &pg->peers[first].allowed_peers_head;
  1326. second_list = &pg->peers[second].allowed_peers_head;
  1327. first_tail = &pg->peers[first].allowed_peers_tail;
  1328. second_tail = &pg->peers[second].allowed_peers_tail;
  1329. break;
  1330. case CONNECT:
  1331. first_list = &pg->peers[first].connect_peers_head;
  1332. second_list = &pg->peers[second].connect_peers_head;
  1333. first_tail = &pg->peers[first].connect_peers_tail;
  1334. second_tail = &pg->peers[second].connect_peers_tail;
  1335. break;
  1336. case BLACKLIST:
  1337. first_list = &pg->peers[first].blacklisted_peers_head;
  1338. second_list = &pg->peers[second].blacklisted_peers_head;
  1339. first_tail = &pg->peers[first].blacklisted_peers_tail;
  1340. second_tail = &pg->peers[second].blacklisted_peers_tail;
  1341. break;
  1342. case WORKING_SET:
  1343. first_list = &pg->peers[first].connect_peers_working_set_head;
  1344. second_list = &pg->peers[second].connect_peers_working_set_head;
  1345. first_tail = &pg->peers[first].connect_peers_working_set_tail;
  1346. second_tail = &pg->peers[second].connect_peers_working_set_tail;
  1347. break;
  1348. default:
  1349. GNUNET_break(0);
  1350. return 0;
  1351. }
  1352. first_iter = *first_list;
  1353. while (first_iter != NULL)
  1354. {
  1355. if (first_iter->index == second)
  1356. {
  1357. GNUNET_CONTAINER_DLL_remove(*first_list, *first_tail, first_iter);
  1358. GNUNET_free(first_iter);
  1359. removed++;
  1360. break;
  1361. }
  1362. first_iter = first_iter->next;
  1363. }
  1364. second_iter = *second_list;
  1365. while (second_iter != NULL)
  1366. {
  1367. if (second_iter->index == first)
  1368. {
  1369. GNUNET_CONTAINER_DLL_remove(*second_list, *second_tail, second_iter);
  1370. GNUNET_free(second_iter);
  1371. removed++;
  1372. break;
  1373. }
  1374. second_iter = second_iter->next;
  1375. }
  1376. #else
  1377. if (GNUNET_YES ==
  1378. GNUNET_CONTAINER_multihashmap_contains (pg->peers[first].blacklisted_peers,
  1379. &hash_second))
  1380. {
  1381. GNUNET_CONTAINER_multihashmap_remove_all (pg->peers[first].blacklisted_peers,
  1382. &hash_second);
  1383. }
  1384. if (GNUNET_YES ==
  1385. GNUNET_CONTAINER_multihashmap_contains (pg->peers[second].blacklisted_peers,
  1386. &hash_first))
  1387. {
  1388. GNUNET_CONTAINER_multihashmap_remove_all (pg->peers[second].blacklisted_peers,
  1389. &hash_first);
  1390. }
  1391. #endif
  1392. return removed;
  1393. }
  1394. /*
  1395. * Add entries to the some list
  1396. *
  1397. * @param pg the peer group we are working with
  1398. * @param first index of the first peer
  1399. * @param second index of the second peer
  1400. * @param list the list type that we should modify
  1401. * @param check GNUNET_YES to check lists before adding
  1402. * GNUNET_NO to force add
  1403. *
  1404. * @return the number of connections added (can be 0, 1 or 2)
  1405. *
  1406. */
  1407. static unsigned int
  1408. add_connections(struct GNUNET_TESTING_PeerGroup *pg, unsigned int first,
  1409. unsigned int second, enum PeerLists list, unsigned int check)
  1410. {
  1411. int added;
  1412. int add_first;
  1413. int add_second;
  1414. struct PeerConnection **first_list;
  1415. struct PeerConnection **second_list;
  1416. struct PeerConnection *first_iter;
  1417. struct PeerConnection *second_iter;
  1418. struct PeerConnection *new_first;
  1419. struct PeerConnection *new_second;
  1420. struct PeerConnection **first_tail;
  1421. struct PeerConnection **second_tail;
  1422. switch (list)
  1423. {
  1424. case ALLOWED:
  1425. first_list = &pg->peers[first].allowed_peers_head;
  1426. second_list = &pg->peers[second].allowed_peers_head;
  1427. first_tail = &pg->peers[first].allowed_peers_tail;
  1428. second_tail = &pg->peers[second].allowed_peers_tail;
  1429. break;
  1430. case CONNECT:
  1431. first_list = &pg->peers[first].connect_peers_head;
  1432. second_list = &pg->peers[second].connect_peers_head;
  1433. first_tail = &pg->peers[first].connect_peers_tail;
  1434. second_tail = &pg->peers[second].connect_peers_tail;
  1435. break;
  1436. case BLACKLIST:
  1437. first_list = &pg->peers[first].blacklisted_peers_head;
  1438. second_list = &pg->peers[second].blacklisted_peers_head;
  1439. first_tail = &pg->peers[first].blacklisted_peers_tail;
  1440. second_tail = &pg->peers[second].blacklisted_peers_tail;
  1441. break;
  1442. case WORKING_SET:
  1443. first_list = &pg->peers[first].connect_peers_working_set_head;
  1444. second_list = &pg->peers[second].connect_peers_working_set_head;
  1445. first_tail = &pg->peers[first].connect_peers_working_set_tail;
  1446. second_tail = &pg->peers[second].connect_peers_working_set_tail;
  1447. break;
  1448. default:
  1449. GNUNET_break(0);
  1450. return 0;
  1451. }
  1452. add_first = GNUNET_YES;
  1453. add_second = GNUNET_YES;
  1454. if (check == GNUNET_YES)
  1455. {
  1456. first_iter = *first_list;
  1457. while (first_iter != NULL)
  1458. {
  1459. if (first_iter->index == second)
  1460. {
  1461. add_first = GNUNET_NO;
  1462. break;
  1463. }
  1464. first_iter = first_iter->next;
  1465. }
  1466. second_iter = *second_list;
  1467. while (second_iter != NULL)
  1468. {
  1469. if (second_iter->index == first)
  1470. {
  1471. add_second = GNUNET_NO;
  1472. break;
  1473. }
  1474. second_iter = second_iter->next;
  1475. }
  1476. }
  1477. added = 0;
  1478. if (add_first)
  1479. {
  1480. new_first = GNUNET_malloc (sizeof (struct PeerConnection));
  1481. new_first->index = second;
  1482. GNUNET_CONTAINER_DLL_insert(*first_list, *first_tail, new_first);
  1483. pg->peers[first].num_connections++;
  1484. added++;
  1485. }
  1486. if (add_second)
  1487. {
  1488. new_second = GNUNET_malloc (sizeof (struct PeerConnection));
  1489. new_second->index = first;
  1490. GNUNET_CONTAINER_DLL_insert(*second_list, *second_tail, new_second);
  1491. pg->peers[second].num_connections++;
  1492. added++;
  1493. }
  1494. return added;
  1495. }
  1496. /**
  1497. * Scale free network construction as described in:
  1498. *
  1499. * "Emergence of Scaling in Random Networks." Science 286, 509-512, 1999.
  1500. *
  1501. * Start with a network of "one" peer, then progressively add
  1502. * peers up to the total number. At each step, iterate over
  1503. * all possible peers and connect new peer based on number of
  1504. * existing connections of the target peer.
  1505. *
  1506. * @param pg the peer group we are dealing with
  1507. * @param proc the connection processor to use
  1508. * @param list the peer list to use
  1509. *
  1510. * @return the number of connections created
  1511. */
  1512. static unsigned int
  1513. create_scale_free(struct GNUNET_TESTING_PeerGroup *pg,
  1514. GNUNET_TESTING_ConnectionProcessor proc, enum PeerLists list)
  1515. {
  1516. unsigned int total_connections;
  1517. unsigned int outer_count;
  1518. unsigned int i;
  1519. unsigned int previous_total_connections;
  1520. double random;
  1521. double probability;
  1522. GNUNET_assert (pg->total > 1);
  1523. /* Add a connection between the first two nodes */
  1524. total_connections = proc (pg, 0, 1, list, GNUNET_YES);
  1525. for (outer_count = 1; outer_count < pg->total; outer_count++)
  1526. {
  1527. previous_total_connections = total_connections;
  1528. for (i = 0; i < outer_count; i++)
  1529. {
  1530. probability = pg->peers[i].num_connections
  1531. / (double) previous_total_connections;
  1532. random
  1533. = ((double) GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK,
  1534. UINT64_MAX))
  1535. / ((double) UINT64_MAX);
  1536. #if VERBOSE_TESTING
  1537. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  1538. "Considering connecting peer %d to peer %d\n",
  1539. outer_count, i);
  1540. #endif
  1541. if (random < probability)
  1542. {
  1543. #if VERBOSE_TESTING
  1544. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  1545. "Connecting peer %d to peer %d\n", outer_count, i);
  1546. #endif
  1547. total_connections += proc (pg, outer_count, i, list, GNUNET_YES);
  1548. }
  1549. }
  1550. }
  1551. return total_connections;
  1552. }
  1553. /**
  1554. * Create a topology given a peer group (set of running peers)
  1555. * and a connection processor. Creates a small world topology
  1556. * according to the rewired ring construction. The basic
  1557. * behavior is that a ring topology is created, but with some
  1558. * probability instead of connecting a peer to the next
  1559. * neighbor in the ring a connection will be created to a peer
  1560. * selected uniformly at random. We use the TESTING
  1561. * PERCENTAGE option to specify what number of
  1562. * connections each peer should have. Default is 2,
  1563. * which makes the ring, any given number is multiplied by
  1564. * the log of the network size; i.e. a PERCENTAGE of 2 makes
  1565. * each peer have on average 2logn connections. The additional
  1566. * connections are made at increasing distance around the ring
  1567. * from the original peer, or to random peers based on the re-
  1568. * wiring probability. The TESTING
  1569. * PROBABILITY option is used as the probability that a given
  1570. * connection is rewired.
  1571. *
  1572. * @param pg the peergroup to create the topology on
  1573. * @param proc the connection processor to call to actually set
  1574. * up connections between two peers
  1575. * @param list the peer list to use
  1576. *
  1577. * @return the number of connections that were set up
  1578. *
  1579. */
  1580. static unsigned int
  1581. create_small_world_ring(struct GNUNET_TESTING_PeerGroup *pg,
  1582. GNUNET_TESTING_ConnectionProcessor proc,
  1583. enum PeerLists list)
  1584. {
  1585. unsigned int i, j;
  1586. int nodeToConnect;
  1587. unsigned int natLog;
  1588. unsigned int randomPeer;
  1589. double random, logNModifier, probability;
  1590. unsigned int smallWorldConnections;
  1591. int connsPerPeer;
  1592. char *p_string;
  1593. int max;
  1594. int min;
  1595. unsigned int useAnd;
  1596. int connect_attempts;
  1597. logNModifier = 0.5; /* FIXME: default value? */
  1598. if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (pg->cfg, "TESTING",
  1599. "PERCENTAGE",
  1600. &p_string))
  1601. {
  1602. if (sscanf (p_string, "%lf", &logNModifier) != 1)
  1603. GNUNET_log (
  1604. GNUNET_ERROR_TYPE_WARNING,
  1605. _
  1606. ("Invalid value `%s' for option `%s' in section `%s': expected float\n"),
  1607. p_string, "LOGNMODIFIER", "TESTING");
  1608. GNUNET_free (p_string);
  1609. }
  1610. probability = 0.5; /* FIXME: default percentage? */
  1611. if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (pg->cfg, "TESTING",
  1612. "PROBABILITY",
  1613. &p_string))
  1614. {
  1615. if (sscanf (p_string, "%lf", &probability) != 1)
  1616. GNUNET_log (
  1617. GNUNET_ERROR_TYPE_WARNING,
  1618. _
  1619. ("Invalid value `%s' for option `%s' in section `%s': expected float\n"),
  1620. p_string, "PERCENTAGE", "TESTING");
  1621. GNUNET_free (p_string);
  1622. }
  1623. natLog = log (pg->total);
  1624. connsPerPeer = ceil (natLog * logNModifier);
  1625. if (connsPerPeer % 2 == 1)
  1626. connsPerPeer += 1;
  1627. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _("Target is %d connections per peer."),
  1628. connsPerPeer);
  1629. smallWorldConnections = 0;
  1630. connect_attempts = 0;
  1631. for (i = 0; i < pg->total; i++)
  1632. {
  1633. useAnd = 0;
  1634. max = i + connsPerPeer / 2;
  1635. min = i - connsPerPeer / 2;
  1636. if (max > pg->total - 1)
  1637. {
  1638. max = max - pg->total;
  1639. useAnd = 1;
  1640. }
  1641. if (min < 0)
  1642. {
  1643. min = pg->total - 1 + min;
  1644. useAnd = 1;
  1645. }
  1646. for (j = 0; j < connsPerPeer / 2; j++)
  1647. {
  1648. random
  1649. = ((double) GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK,
  1650. UINT64_MAX)
  1651. / ((double) UINT64_MAX));
  1652. if (random < probability)
  1653. {
  1654. /* Connect to uniformly selected random peer */
  1655. randomPeer
  1656. = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
  1657. pg->total);
  1658. while ((((randomPeer < max) && (randomPeer > min)) && (useAnd
  1659. == 0)) || (((randomPeer > min) || (randomPeer < max))
  1660. && (useAnd == 1)))
  1661. {
  1662. randomPeer
  1663. = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
  1664. pg->total);
  1665. }
  1666. smallWorldConnections += proc (pg, i, randomPeer, list,
  1667. GNUNET_YES);
  1668. }
  1669. else
  1670. {
  1671. nodeToConnect = i + j + 1;
  1672. if (nodeToConnect > pg->total - 1)
  1673. {
  1674. nodeToConnect = nodeToConnect - pg->total;
  1675. }
  1676. connect_attempts += proc (pg, i, nodeToConnect, list, GNUNET_YES);
  1677. }
  1678. }
  1679. }
  1680. connect_attempts += smallWorldConnections;
  1681. return connect_attempts;
  1682. }
  1683. /**
  1684. * Create a topology given a peer group (set of running peers)
  1685. * and a connection processor.
  1686. *
  1687. * @param pg the peergroup to create the topology on
  1688. * @param proc the connection processor to call to actually set
  1689. * up connections between two peers
  1690. * @param list the peer list to use
  1691. *
  1692. * @return the number of connections that were set up
  1693. *
  1694. */
  1695. static unsigned int
  1696. create_nated_internet(struct GNUNET_TESTING_PeerGroup *pg,
  1697. GNUNET_TESTING_ConnectionProcessor proc,
  1698. enum PeerLists list)
  1699. {
  1700. unsigned int outer_count, inner_count;
  1701. unsigned int cutoff;
  1702. int connect_attempts;
  1703. double nat_percentage;
  1704. char *p_string;
  1705. nat_percentage = 0.6; /* FIXME: default percentage? */
  1706. if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (pg->cfg, "TESTING",
  1707. "PERCENTAGE",
  1708. &p_string))
  1709. {
  1710. if (sscanf (p_string, "%lf", &nat_percentage) != 1)
  1711. GNUNET_log (
  1712. GNUNET_ERROR_TYPE_WARNING,
  1713. _
  1714. ("Invalid value `%s' for option `%s' in section `%s': expected float\n"),
  1715. p_string, "PERCENTAGE", "TESTING");
  1716. GNUNET_free (p_string);
  1717. }
  1718. cutoff = (unsigned int) (nat_percentage * pg->total);
  1719. connect_attempts = 0;
  1720. for (outer_count = 0; outer_count < pg->total - 1; outer_count++)
  1721. {
  1722. for (inner_count = outer_count + 1; inner_count < pg->total; inner_count++)
  1723. {
  1724. if ((outer_count > cutoff) || (inner_count > cutoff))
  1725. {
  1726. #if VERBOSE_TESTING
  1727. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  1728. "Connecting peer %d to peer %d\n",
  1729. outer_count, inner_count);
  1730. #endif
  1731. connect_attempts += proc (pg, outer_count, inner_count, list,
  1732. GNUNET_YES);
  1733. }
  1734. }
  1735. }
  1736. return connect_attempts;
  1737. }
  1738. #if TOPOLOGY_HACK
  1739. /**
  1740. * Create a topology given a peer group (set of running peers)
  1741. * and a connection processor.
  1742. *
  1743. * @param pg the peergroup to create the topology on
  1744. * @param proc the connection processor to call to actually set
  1745. * up connections between two peers
  1746. * @param list the peer list to use
  1747. *
  1748. * @return the number of connections that were set up
  1749. *
  1750. */
  1751. static unsigned int
  1752. create_nated_internet_copy(struct GNUNET_TESTING_PeerGroup *pg,
  1753. GNUNET_TESTING_ConnectionProcessor proc,
  1754. enum PeerLists list)
  1755. {
  1756. unsigned int outer_count, inner_count;
  1757. unsigned int cutoff;
  1758. int connect_attempts;
  1759. double nat_percentage;
  1760. char *p_string;
  1761. unsigned int count;
  1762. struct ProgressMeter *conn_meter;
  1763. nat_percentage = 0.6; /* FIXME: default percentage? */
  1764. if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (pg->cfg, "TESTING",
  1765. "PERCENTAGE",
  1766. &p_string))
  1767. {
  1768. if (sscanf (p_string, "%lf", &nat_percentage) != 1)
  1769. GNUNET_log (
  1770. GNUNET_ERROR_TYPE_WARNING,
  1771. _
  1772. ("Invalid value `%s' for option `%s' in section `%s': expected float\n"),
  1773. p_string, "PERCENTAGE", "TESTING");
  1774. GNUNET_free (p_string);
  1775. }
  1776. cutoff = (unsigned int) (nat_percentage * pg->total);
  1777. count = 0;
  1778. for (outer_count = 0; outer_count < pg->total - 1; outer_count++)
  1779. {
  1780. for (inner_count = outer_count + 1; inner_count < pg->total; inner_count++)
  1781. {
  1782. if ((outer_count > cutoff) || (inner_count > cutoff))
  1783. {
  1784. count++;
  1785. }
  1786. }
  1787. }
  1788. conn_meter = create_meter (count, "NAT COPY", GNUNET_YES);
  1789. connect_attempts = 0;
  1790. for (outer_count = 0; outer_count < pg->total - 1; outer_count++)
  1791. {
  1792. for (inner_count = outer_count + 1; inner_count < pg->total; inner_count++)
  1793. {
  1794. if ((outer_count > cutoff) || (inner_count > cutoff))
  1795. {
  1796. #if VERBOSE_TESTING
  1797. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  1798. "Connecting peer %d to peer %d\n",
  1799. outer_count, inner_count);
  1800. #endif
  1801. connect_attempts += proc (pg, outer_count, inner_count, list,
  1802. GNUNET_YES);
  1803. add_connections (pg, outer_count, inner_count, ALLOWED, GNUNET_NO);
  1804. update_meter (conn_meter);
  1805. }
  1806. }
  1807. }
  1808. free_meter (conn_meter);
  1809. return connect_attempts;
  1810. }
  1811. #endif
  1812. /**
  1813. * Create a topology given a peer group (set of running peers)
  1814. * and a connection processor.
  1815. *
  1816. * @param pg the peergroup to create the topology on
  1817. * @param proc the connection processor to call to actually set
  1818. * up connections between two peers
  1819. * @param list the peer list to use
  1820. *
  1821. * @return the number of connections that were set up
  1822. *
  1823. */
  1824. static unsigned int
  1825. create_small_world(struct GNUNET_TESTING_PeerGroup *pg,
  1826. GNUNET_TESTING_ConnectionProcessor proc, enum PeerLists list)
  1827. {
  1828. unsigned int i, j, k;
  1829. unsigned int square;
  1830. unsigned int rows;
  1831. unsigned int cols;
  1832. unsigned int toggle = 1;
  1833. unsigned int nodeToConnect;
  1834. unsigned int natLog;
  1835. unsigned int node1Row;
  1836. unsigned int node1Col;
  1837. unsigned int node2Row;
  1838. unsigned int node2Col;
  1839. unsigned int distance;
  1840. double probability, random, percentage;
  1841. unsigned int smallWorldConnections;
  1842. unsigned int small_world_it;
  1843. char *p_string;
  1844. int connect_attempts;
  1845. square = floor (sqrt (pg->total));
  1846. rows = square;
  1847. cols = square;
  1848. percentage = 0.5; /* FIXME: default percentage? */
  1849. if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (pg->cfg, "TESTING",
  1850. "PERCENTAGE",
  1851. &p_string))
  1852. {
  1853. if (sscanf (p_string, "%lf", &percentage) != 1)
  1854. GNUNET_log (
  1855. GNUNET_ERROR_TYPE_WARNING,
  1856. _
  1857. ("Invalid value `%s' for option `%s' in section `%s': expected float\n"),
  1858. p_string, "PERCENTAGE", "TESTING");
  1859. GNUNET_free (p_string);
  1860. }
  1861. if (percentage < 0.0)
  1862. {
  1863. GNUNET_log (
  1864. GNUNET_ERROR_TYPE_WARNING,
  1865. _
  1866. ("Invalid value `%s' for option `%s' in section `%s': got %f, needed value greater than 0\n"),
  1867. "PERCENTAGE", "TESTING", percentage);
  1868. percentage = 0.5;
  1869. }
  1870. probability = 0.5; /* FIXME: default percentage? */
  1871. if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (pg->cfg, "TESTING",
  1872. "PROBABILITY",
  1873. &p_string))
  1874. {
  1875. if (sscanf (p_string, "%lf", &probability) != 1)
  1876. GNUNET_log (
  1877. GNUNET_ERROR_TYPE_WARNING,
  1878. _
  1879. ("Invalid value `%s' for option `%s' in section `%s': expected float\n"),
  1880. p_string, "PROBABILITY", "TESTING");
  1881. GNUNET_free (p_string);
  1882. }
  1883. if (square * square != pg->total)
  1884. {
  1885. while (rows * cols < pg->total)
  1886. {
  1887. if (toggle % 2 == 0)
  1888. rows++;
  1889. else
  1890. cols++;
  1891. toggle++;
  1892. }
  1893. }
  1894. #if VERBOSE_TESTING
  1895. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  1896. _
  1897. ("Connecting nodes in 2d torus topology: %u rows %u columns\n"),
  1898. rows, cols);
  1899. #endif
  1900. connect_attempts = 0;
  1901. /* Rows and columns are all sorted out, now iterate over all nodes and connect each
  1902. * to the node to its right and above. Once this is over, we'll have our torus!
  1903. * Special case for the last node (if the rows and columns are not equal), connect
  1904. * to the first in the row to maintain topology.
  1905. */
  1906. for (i = 0; i < pg->total; i++)
  1907. {
  1908. /* First connect to the node to the right */
  1909. if (((i + 1) % cols != 0) && (i + 1 != pg->total))
  1910. nodeToConnect = i + 1;
  1911. else if (i + 1 == pg->total)
  1912. nodeToConnect = rows * cols - cols;
  1913. else
  1914. nodeToConnect = i - cols + 1;
  1915. connect_attempts += proc (pg, i, nodeToConnect, list, GNUNET_YES);
  1916. if (i < cols)
  1917. {
  1918. nodeToConnect = (rows * cols) - cols + i;
  1919. if (nodeToConnect >= pg->total)
  1920. nodeToConnect -= cols;
  1921. }
  1922. else
  1923. nodeToConnect = i - cols;
  1924. if (nodeToConnect < pg->total)
  1925. connect_attempts += proc (pg, i, nodeToConnect, list, GNUNET_YES);
  1926. }
  1927. natLog = log (pg->total);
  1928. #if VERBOSE_TESTING > 2
  1929. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  1930. _("natural log of %d is %d, will run %d iterations\n"),
  1931. pg->total, natLog, (int) (natLog * percentage));
  1932. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  1933. _("Total connections added thus far: %u!\n"), connect_attempts);
  1934. #endif
  1935. smallWorldConnections = 0;
  1936. small_world_it = (unsigned int) (natLog * percentage);
  1937. if (small_world_it < 1)
  1938. small_world_it = 1;
  1939. GNUNET_assert (small_world_it > 0 && small_world_it < (unsigned int) -1);
  1940. for (i = 0; i < small_world_it; i++)
  1941. {
  1942. for (j = 0; j < pg->total; j++)
  1943. {
  1944. /* Determine the row and column of node at position j on the 2d torus */
  1945. node1Row = j / cols;
  1946. node1Col = j - (node1Row * cols);
  1947. for (k = 0; k < pg->total; k++)
  1948. {
  1949. /* Determine the row and column of node at position k on the 2d torus */
  1950. node2Row = k / cols;
  1951. node2Col = k - (node2Row * cols);
  1952. /* Simple Cartesian distance */
  1953. distance = abs (node1Row - node2Row) + abs (node1Col - node2Col);
  1954. if (distance > 1)
  1955. {
  1956. /* Calculate probability as 1 over the square of the distance */
  1957. probability = 1.0 / (distance * distance);
  1958. /* Choose a random value between 0 and 1 */
  1959. random
  1960. = ((double) GNUNET_CRYPTO_random_u64 (
  1961. GNUNET_CRYPTO_QUALITY_WEAK,
  1962. UINT64_MAX))
  1963. / ((double) UINT64_MAX);
  1964. /* If random < probability, then connect the two nodes */
  1965. if (random < probability)
  1966. smallWorldConnections += proc (pg, j, k, list, GNUNET_YES);
  1967. }
  1968. }
  1969. }
  1970. }
  1971. connect_attempts += smallWorldConnections;
  1972. #if VERBOSE_TESTING > 2
  1973. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  1974. _("Total connections added for small world: %d!\n"),
  1975. smallWorldConnections);
  1976. #endif
  1977. return connect_attempts;
  1978. }
  1979. /**
  1980. * Create a topology given a peer group (set of running peers)
  1981. * and a connection processor.
  1982. *
  1983. * @param pg the peergroup to create the topology on
  1984. * @param proc the connection processor to call to actually set
  1985. * up connections between two peers
  1986. * @param list the peer list to use
  1987. *
  1988. * @return the number of connections that were set up
  1989. *
  1990. */
  1991. static unsigned int
  1992. create_erdos_renyi(struct GNUNET_TESTING_PeerGroup *pg,
  1993. GNUNET_TESTING_ConnectionProcessor proc, enum PeerLists list)
  1994. {
  1995. double temp_rand;
  1996. unsigned int outer_count;
  1997. unsigned int inner_count;
  1998. int connect_attempts;
  1999. double probability;
  2000. char *p_string;
  2001. probability = 0.5; /* FIXME: default percentage? */
  2002. if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (pg->cfg, "TESTING",
  2003. "PROBABILITY",
  2004. &p_string))
  2005. {
  2006. if (sscanf (p_string, "%lf", &probability) != 1)
  2007. GNUNET_log (
  2008. GNUNET_ERROR_TYPE_WARNING,
  2009. _
  2010. ("Invalid value `%s' for option `%s' in section `%s': expected float\n"),
  2011. p_string, "PROBABILITY", "TESTING");
  2012. GNUNET_free (p_string);
  2013. }
  2014. connect_attempts = 0;
  2015. for (outer_count = 0; outer_count < pg->total - 1; outer_count++)
  2016. {
  2017. for (inner_count = outer_count + 1; inner_count < pg->total; inner_count++)
  2018. {
  2019. temp_rand
  2020. = ((double) GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK,
  2021. UINT64_MAX))
  2022. / ((double) UINT64_MAX);
  2023. #if VERBOSE_TESTING
  2024. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  2025. _("rand is %f probability is %f\n"), temp_rand,
  2026. probability);
  2027. #endif
  2028. if (temp_rand < probability)
  2029. {
  2030. connect_attempts += proc (pg, outer_count, inner_count, list,
  2031. GNUNET_YES);
  2032. }
  2033. }
  2034. }
  2035. return connect_attempts;
  2036. }
  2037. /**
  2038. * Create a topology given a peer group (set of running peers)
  2039. * and a connection processor. This particular function creates
  2040. * the connections for a 2d-torus, plus additional "closest"
  2041. * connections per peer.
  2042. *
  2043. * @param pg the peergroup to create the topology on
  2044. * @param proc the connection processor to call to actually set
  2045. * up connections between two peers
  2046. * @param list the peer list to use
  2047. *
  2048. * @return the number of connections that were set up
  2049. *
  2050. */
  2051. static unsigned int
  2052. create_2d_torus(struct GNUNET_TESTING_PeerGroup *pg,
  2053. GNUNET_TESTING_ConnectionProcessor proc, enum PeerLists list)
  2054. {
  2055. unsigned int i;
  2056. unsigned int square;
  2057. unsigned int rows;
  2058. unsigned int cols;
  2059. unsigned int toggle = 1;
  2060. unsigned int nodeToConnect;
  2061. int connect_attempts;
  2062. connect_attempts = 0;
  2063. square = floor (sqrt (pg->total));
  2064. rows = square;
  2065. cols = square;
  2066. if (square * square != pg->total)
  2067. {
  2068. while (rows * cols < pg->total)
  2069. {
  2070. if (toggle % 2 == 0)
  2071. rows++;
  2072. else
  2073. cols++;
  2074. toggle++;
  2075. }
  2076. }
  2077. #if VERBOSE_TESTING
  2078. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  2079. _
  2080. ("Connecting nodes in 2d torus topology: %u rows %u columns\n"),
  2081. rows, cols);
  2082. #endif
  2083. /* Rows and columns are all sorted out, now iterate over all nodes and connect each
  2084. * to the node to its right and above. Once this is over, we'll have our torus!
  2085. * Special case for the last node (if the rows and columns are not equal), connect
  2086. * to the first in the row to maintain topology.
  2087. */
  2088. for (i = 0; i < pg->total; i++)
  2089. {
  2090. /* First connect to the node to the right */
  2091. if (((i + 1) % cols != 0) && (i + 1 != pg->total))
  2092. nodeToConnect = i + 1;
  2093. else if (i + 1 == pg->total)
  2094. nodeToConnect = rows * cols - cols;
  2095. else
  2096. nodeToConnect = i - cols + 1;
  2097. #if VERBOSE_TESTING
  2098. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  2099. "Connecting peer %d to peer %d\n", i, nodeToConnect);
  2100. #endif
  2101. connect_attempts += proc (pg, i, nodeToConnect, list, GNUNET_YES);
  2102. /* Second connect to the node immediately above */
  2103. if (i < cols)
  2104. {
  2105. nodeToConnect = (rows * cols) - cols + i;
  2106. if (nodeToConnect >= pg->total)
  2107. nodeToConnect -= cols;
  2108. }
  2109. else
  2110. nodeToConnect = i - cols;
  2111. if (nodeToConnect < pg->total)
  2112. {
  2113. #if VERBOSE_TESTING
  2114. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  2115. "Connecting peer %d to peer %d\n", i, nodeToConnect);
  2116. #endif
  2117. connect_attempts += proc (pg, i, nodeToConnect, list, GNUNET_YES);
  2118. }
  2119. }
  2120. return connect_attempts;
  2121. }
  2122. /**
  2123. * Create a topology given a peer group (set of running peers)
  2124. * and a connection processor.
  2125. *
  2126. * @param pg the peergroup to create the topology on
  2127. * @param proc the connection processor to call to actually set
  2128. * up connections between two peers
  2129. * @param list the peer list to use
  2130. * @param check does the connection processor need to check before
  2131. * performing an action on the list?
  2132. *
  2133. * @return the number of connections that were set up
  2134. *
  2135. */
  2136. static unsigned int
  2137. create_clique(struct GNUNET_TESTING_PeerGroup *pg,
  2138. GNUNET_TESTING_ConnectionProcessor proc, enum PeerLists list,
  2139. unsigned int check)
  2140. {
  2141. unsigned int outer_count;
  2142. unsigned int inner_count;
  2143. int connect_attempts;
  2144. struct ProgressMeter *conn_meter;
  2145. connect_attempts = 0;
  2146. conn_meter = create_meter ((((pg->total * pg->total) + pg->total) / 2)
  2147. - pg->total, "Create Clique ", GNUNET_NO);
  2148. for (outer_count = 0; outer_count < pg->total - 1; outer_count++)
  2149. {
  2150. for (inner_count = outer_count + 1; inner_count < pg->total; inner_count++)
  2151. {
  2152. #if VERBOSE_TESTING
  2153. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  2154. "Connecting peer %d to peer %d\n",
  2155. outer_count, inner_count);
  2156. #endif
  2157. connect_attempts += proc (pg, outer_count, inner_count, list, check);
  2158. update_meter (conn_meter);
  2159. }
  2160. }
  2161. reset_meter (conn_meter);
  2162. free_meter (conn_meter);
  2163. return connect_attempts;
  2164. }
  2165. #if !OLD
  2166. /**
  2167. * Iterator over hash map entries.
  2168. *
  2169. * @param cls closure the peer group
  2170. * @param key the key stored in the hashmap is the
  2171. * index of the peer to connect to
  2172. * @param value value in the hash map, handle to the peer daemon
  2173. * @return GNUNET_YES if we should continue to
  2174. * iterate,
  2175. * GNUNET_NO if not.
  2176. */
  2177. static int
  2178. unblacklist_iterator (void *cls,
  2179. const GNUNET_HashCode * key,
  2180. void *value)
  2181. {
  2182. struct UnblacklistContext *un_ctx = cls;
  2183. uint32_t second_pos;
  2184. uid_from_hash (key, &second_pos);
  2185. unblacklist_connections(un_ctx->pg, un_ctx->first_uid, second_pos);
  2186. return GNUNET_YES;
  2187. }
  2188. #endif
  2189. #if !OLD
  2190. /**
  2191. * Create a blacklist topology based on the allowed topology
  2192. * which disallows any connections not in the allowed topology
  2193. * at the transport level.
  2194. *
  2195. * @param pg the peergroup to create the topology on
  2196. * @param proc the connection processor to call to allow
  2197. * up connections between two peers
  2198. *
  2199. * @return the number of connections that were set up
  2200. *
  2201. */
  2202. static unsigned int
  2203. copy_allowed (struct GNUNET_TESTING_PeerGroup *pg,
  2204. GNUNET_TESTING_ConnectionProcessor proc)
  2205. {
  2206. unsigned int count;
  2207. unsigned int total;
  2208. struct PeerConnection *iter;
  2209. #if !OLD
  2210. struct UnblacklistContext un_ctx;
  2211. un_ctx.pg = pg;
  2212. #endif
  2213. total = 0;
  2214. for (count = 0; count < pg->total - 1; count++)
  2215. {
  2216. #if OLD
  2217. iter = pg->peers[count].allowed_peers_head;
  2218. while (iter != NULL)
  2219. {
  2220. remove_connections (pg, count, iter->index, BLACKLIST, GNUNET_YES);
  2221. //unblacklist_connections(pg, count, iter->index);
  2222. iter = iter->next;
  2223. }
  2224. #else
  2225. un_ctx.first_uid = count;
  2226. total += GNUNET_CONTAINER_multihashmap_iterate(pg->peers[count].allowed_peers,
  2227. &unblacklist_iterator,
  2228. &un_ctx);
  2229. #endif
  2230. }
  2231. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  2232. "Unblacklisted %u peers\n",
  2233. total);
  2234. return total;
  2235. }
  2236. #endif
  2237. /**
  2238. * Create a topology given a peer group (set of running peers)
  2239. * and a connection processor.
  2240. *
  2241. * @param pg the peergroup to create the topology on
  2242. * @param proc the connection processor to call to actually set
  2243. * up connections between two peers
  2244. * @param list which list should be modified
  2245. *
  2246. * @return the number of connections that were set up
  2247. *
  2248. */
  2249. static unsigned int
  2250. create_line(struct GNUNET_TESTING_PeerGroup *pg,
  2251. GNUNET_TESTING_ConnectionProcessor proc, enum PeerLists list)
  2252. {
  2253. unsigned int count;
  2254. unsigned int connect_attempts;
  2255. connect_attempts = 0;
  2256. /* Connect each peer to the next highest numbered peer */
  2257. for (count = 0; count < pg->total - 1; count++)
  2258. {
  2259. #if VERBOSE_TESTING
  2260. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  2261. "Connecting peer %d to peer %d\n",
  2262. count, count + 1);
  2263. #endif
  2264. connect_attempts += proc (pg, count, count + 1, list, GNUNET_YES);
  2265. }
  2266. return connect_attempts;
  2267. }
  2268. /**
  2269. * Create a topology given a peer group (set of running peers)
  2270. * and a connection processor.
  2271. *
  2272. * @param pg the peergroup to create the topology on
  2273. * @param filename the file to read topology information from
  2274. * @param proc the connection processor to call to actually set
  2275. * up connections between two peers
  2276. * @param list the peer list to use
  2277. *
  2278. * @return the number of connections that were set up
  2279. *
  2280. */
  2281. static unsigned int
  2282. create_from_file(struct GNUNET_TESTING_PeerGroup *pg, char *filename,
  2283. GNUNET_TESTING_ConnectionProcessor proc, enum PeerLists list)
  2284. {
  2285. int connect_attempts;
  2286. unsigned int first_peer_index;
  2287. unsigned int second_peer_index;
  2288. struct stat frstat;
  2289. int count;
  2290. char *data;
  2291. const char *buf;
  2292. unsigned int total_peers;
  2293. enum States curr_state;
  2294. connect_attempts = 0;
  2295. if (GNUNET_OK != GNUNET_DISK_file_test (filename))
  2296. GNUNET_DISK_fn_write (filename, NULL, 0, GNUNET_DISK_PERM_USER_READ);
  2297. if ((0 != STAT (filename, &frstat)) || (frstat.st_size == 0))
  2298. {
  2299. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  2300. "Could not open file `%s' specified for topology!", filename);
  2301. return connect_attempts;
  2302. }
  2303. data = GNUNET_malloc_large (frstat.st_size);
  2304. GNUNET_assert(data != NULL);
  2305. if (frstat.st_size != GNUNET_DISK_fn_read (filename, data, frstat.st_size))
  2306. {
  2307. GNUNET_log (
  2308. GNUNET_ERROR_TYPE_ERROR,
  2309. "Could not read file %s specified for host list, ending test!",
  2310. filename);
  2311. GNUNET_free (data);
  2312. return connect_attempts;
  2313. }
  2314. buf = data;
  2315. count = 0;
  2316. first_peer_index = 0;
  2317. /* First line should contain a single integer, specifying the number of peers */
  2318. /* Each subsequent line should contain this format PEER_INDEX:OTHER_PEER_INDEX[,...] */
  2319. curr_state = NUM_PEERS;
  2320. while (count < frstat.st_size - 1)
  2321. {
  2322. if ((buf[count] == '\n') || (buf[count] == ' '))
  2323. {
  2324. count++;
  2325. continue;
  2326. }
  2327. switch (curr_state)
  2328. {
  2329. case NUM_PEERS:
  2330. errno = 0;
  2331. total_peers = strtoul(&buf[count], NULL, 10);
  2332. if (errno != 0)
  2333. {
  2334. GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
  2335. "Failed to read number of peers from topology file!\n");
  2336. GNUNET_free (data);
  2337. return connect_attempts;
  2338. }
  2339. GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
  2340. "Read %u total peers in topology\n", total_peers);
  2341. GNUNET_assert(total_peers == pg->total);
  2342. curr_state = PEER_INDEX;
  2343. while ((buf[count] != '\n') && (count < frstat.st_size - 1))
  2344. count++;
  2345. count++;
  2346. break;
  2347. case PEER_INDEX:
  2348. errno = 0;
  2349. first_peer_index = strtoul(&buf[count], NULL, 10);
  2350. if (errno != 0)
  2351. {
  2352. GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
  2353. "Failed to read peer index from topology file!\n");
  2354. GNUNET_free (data);
  2355. return connect_attempts;
  2356. }
  2357. while ((buf[count] != ':') && (count < frstat.st_size - 1))
  2358. count++;
  2359. count++;
  2360. curr_state = OTHER_PEER_INDEX;
  2361. break;
  2362. case COLON:
  2363. if (1 == sscanf (&buf[count], ":"))
  2364. curr_state = OTHER_PEER_INDEX;
  2365. count++;
  2366. break;
  2367. case OTHER_PEER_INDEX:
  2368. errno = 0;
  2369. second_peer_index = strtoul(&buf[count], NULL, 10);
  2370. if (errno != 0)
  2371. {
  2372. GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
  2373. "Failed to peer index from topology file!\n");
  2374. GNUNET_free (data);
  2375. return connect_attempts;
  2376. }
  2377. /* Assume file is written with first peer 1, but array index is 0 */
  2378. connect_attempts += proc (pg, first_peer_index - 1, second_peer_index
  2379. - 1, list, GNUNET_YES);
  2380. while ((buf[count] != '\n') && (buf[count] != ',') && (count
  2381. < frstat.st_size - 1))
  2382. count++;
  2383. if (buf[count] == '\n')
  2384. {
  2385. curr_state = PEER_INDEX;
  2386. }
  2387. else if (buf[count] != ',')
  2388. {
  2389. curr_state = OTHER_PEER_INDEX;
  2390. }
  2391. count++;
  2392. break;
  2393. default:
  2394. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  2395. "Found bad data in topology file while in state %d!\n",
  2396. curr_state);
  2397. GNUNET_break(0);
  2398. GNUNET_free (data);
  2399. return connect_attempts;
  2400. }
  2401. }
  2402. GNUNET_free (data);
  2403. return connect_attempts;
  2404. }
  2405. /**
  2406. * Create a topology given a peer group (set of running peers)
  2407. * and a connection processor.
  2408. *
  2409. * @param pg the peergroup to create the topology on
  2410. * @param proc the connection processor to call to actually set
  2411. * up connections between two peers
  2412. * @param list the peer list to use
  2413. *
  2414. * @return the number of connections that were set up
  2415. *
  2416. */
  2417. static unsigned int
  2418. create_ring(struct GNUNET_TESTING_PeerGroup *pg,
  2419. GNUNET_TESTING_ConnectionProcessor proc, enum PeerLists list)
  2420. {
  2421. unsigned int count;
  2422. int connect_attempts;
  2423. connect_attempts = 0;
  2424. /* Connect each peer to the next highest numbered peer */
  2425. for (count = 0; count < pg->total - 1; count++)
  2426. {
  2427. #if VERBOSE_TESTING
  2428. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  2429. "Connecting peer %d to peer %d\n", count, count + 1);
  2430. #endif
  2431. connect_attempts += proc (pg, count, count + 1, list, GNUNET_YES);
  2432. }
  2433. /* Connect the last peer to the first peer */
  2434. connect_attempts += proc (pg, pg->total - 1, 0, list, GNUNET_YES);
  2435. return connect_attempts;
  2436. }
  2437. #if !OLD
  2438. /**
  2439. * Iterator for writing friends of a peer to a file.
  2440. *
  2441. * @param cls closure, an open writable file handle
  2442. * @param key the key the daemon was stored under
  2443. * @param value the GNUNET_TESTING_Daemon that needs to be written.
  2444. *
  2445. * @return GNUNET_YES to continue iteration
  2446. *
  2447. * TODO: Could replace friend_file_iterator and blacklist_file_iterator
  2448. * with a single file_iterator that takes a closure which contains
  2449. * the prefix to write before the peer. Then this could be used
  2450. * for blacklisting multiple transports and writing the friend
  2451. * file. I'm sure *someone* will complain loudly about other
  2452. * things that negate these functions even existing so no point in
  2453. * "fixing" now.
  2454. */
  2455. static int
  2456. friend_file_iterator (void *cls, const GNUNET_HashCode * key, void *value)
  2457. {
  2458. FILE *temp_friend_handle = cls;
  2459. struct GNUNET_TESTING_Daemon *peer = value;
  2460. struct GNUNET_PeerIdentity *temppeer;
  2461. struct GNUNET_CRYPTO_HashAsciiEncoded peer_enc;
  2462. temppeer = &peer->id;
  2463. GNUNET_CRYPTO_hash_to_enc (&temppeer->hashPubKey, &peer_enc);
  2464. fprintf (temp_friend_handle, "%s\n", (char *) &peer_enc);
  2465. return GNUNET_YES;
  2466. }
  2467. struct BlacklistContext
  2468. {
  2469. /*
  2470. * The (open) file handle to write to
  2471. */
  2472. FILE *temp_file_handle;
  2473. /*
  2474. * The transport that this peer will be blacklisted on.
  2475. */
  2476. char *transport;
  2477. };
  2478. /**
  2479. * Iterator for writing blacklist data to appropriate files.
  2480. *
  2481. * @param cls closure, an open writable file handle
  2482. * @param key the key the daemon was stored under
  2483. * @param value the GNUNET_TESTING_Daemon that needs to be written.
  2484. *
  2485. * @return GNUNET_YES to continue iteration
  2486. */
  2487. static int
  2488. blacklist_file_iterator (void *cls, const GNUNET_HashCode * key, void *value)
  2489. {
  2490. struct BlacklistContext *blacklist_ctx = cls;
  2491. struct GNUNET_TESTING_Daemon *peer = value;
  2492. struct GNUNET_PeerIdentity *temppeer;
  2493. struct GNUNET_CRYPTO_HashAsciiEncoded peer_enc;
  2494. temppeer = &peer->id;
  2495. GNUNET_CRYPTO_hash_to_enc (&temppeer->hashPubKey, &peer_enc);
  2496. GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Writing entry %s:%s to file\n", blacklist_ctx->transport, (char *) &peer_enc);
  2497. fprintf (blacklist_ctx->temp_file_handle, "%s:%s\n",
  2498. blacklist_ctx->transport, (char *) &peer_enc);
  2499. return GNUNET_YES;
  2500. }
  2501. #endif
  2502. /*
  2503. * Create the friend files based on the PeerConnection's
  2504. * of each peer in the peer group, and copy the files
  2505. * to the appropriate place
  2506. *
  2507. * @param pg the peer group we are dealing with
  2508. */
  2509. static int
  2510. create_and_copy_friend_files(struct GNUNET_TESTING_PeerGroup *pg)
  2511. {
  2512. FILE *temp_friend_handle;
  2513. unsigned int pg_iter;
  2514. char *temp_service_path;
  2515. struct GNUNET_OS_Process **procarr;
  2516. char *arg;
  2517. char *mytemp;
  2518. #if NOT_STUPID
  2519. enum GNUNET_OS_ProcessStatusType type;
  2520. unsigned long return_code;
  2521. int count;
  2522. int max_wait = 10;
  2523. #endif
  2524. int ret;
  2525. ret = GNUNET_OK;
  2526. #if OLD
  2527. struct GNUNET_CRYPTO_HashAsciiEncoded peer_enc;
  2528. struct PeerConnection *conn_iter;
  2529. #endif
  2530. procarr = GNUNET_malloc (sizeof (struct GNUNET_OS_Process *) * pg->total);
  2531. for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
  2532. {
  2533. mytemp = GNUNET_DISK_mktemp ("friends");
  2534. GNUNET_assert (mytemp != NULL);
  2535. temp_friend_handle = fopen (mytemp, "wt");
  2536. GNUNET_assert (temp_friend_handle != NULL);
  2537. #if OLD
  2538. conn_iter = pg->peers[pg_iter].allowed_peers_head;
  2539. while (conn_iter != NULL)
  2540. {
  2541. GNUNET_CRYPTO_hash_to_enc (
  2542. &pg->peers[conn_iter->index].daemon->id.hashPubKey,
  2543. &peer_enc);
  2544. fprintf (temp_friend_handle, "%s\n", (char *) &peer_enc);
  2545. conn_iter = conn_iter->next;
  2546. }
  2547. #else
  2548. GNUNET_CONTAINER_multihashmap_iterate (pg->peers[pg_iter].allowed_peers,
  2549. &friend_file_iterator,
  2550. temp_friend_handle);
  2551. #endif
  2552. fclose (temp_friend_handle);
  2553. if (GNUNET_OK
  2554. != GNUNET_CONFIGURATION_get_value_string (pg->peers[pg_iter].
  2555. daemon->cfg,
  2556. "PATHS", "SERVICEHOME",
  2557. &temp_service_path))
  2558. {
  2559. GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
  2560. _("No `%s' specified in peer configuration in section `%s', cannot copy friends file!\n"),
  2561. "SERVICEHOME", "PATHS");
  2562. if (UNLINK (mytemp) != 0)
  2563. GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
  2564. "unlink",
  2565. mytemp);
  2566. GNUNET_free (mytemp);
  2567. break;
  2568. }
  2569. if (pg->peers[pg_iter].daemon->hostname == NULL) /* Local, just copy the file */
  2570. {
  2571. GNUNET_asprintf (&arg, "%s/friends", temp_service_path);
  2572. procarr[pg_iter] = GNUNET_OS_start_process (NULL, NULL, "mv", "mv",
  2573. mytemp, arg, NULL);
  2574. GNUNET_assert(procarr[pg_iter] != NULL);
  2575. #if VERBOSE_TESTING
  2576. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  2577. "Copying file with command cp %s %s\n",
  2578. mytemp,
  2579. arg);
  2580. #endif
  2581. ret = GNUNET_OS_process_wait (procarr[pg_iter]); /* FIXME: schedule this, throttle! */
  2582. GNUNET_OS_process_close (procarr[pg_iter]);
  2583. GNUNET_free (arg);
  2584. }
  2585. else /* Remote, scp the file to the correct place */
  2586. {
  2587. if (NULL != pg->peers[pg_iter].daemon->username)
  2588. GNUNET_asprintf (&arg, "%s@%s:%s/friends",
  2589. pg->peers[pg_iter].daemon->username,
  2590. pg->peers[pg_iter].daemon->hostname,
  2591. temp_service_path);
  2592. else
  2593. GNUNET_asprintf (&arg, "%s:%s/friends",
  2594. pg->peers[pg_iter].daemon->hostname,
  2595. temp_service_path);
  2596. procarr[pg_iter] = GNUNET_OS_start_process (NULL, NULL, "scp", "scp",
  2597. mytemp, arg, NULL);
  2598. GNUNET_assert(procarr[pg_iter] != NULL);
  2599. ret = GNUNET_OS_process_wait (procarr[pg_iter]); /* FIXME: schedule this, throttle! */
  2600. GNUNET_OS_process_close (procarr[pg_iter]);
  2601. if (ret != GNUNET_OK)
  2602. {
  2603. /* FIXME: free contents of 'procarr' array */
  2604. GNUNET_free (procarr);
  2605. GNUNET_free (temp_service_path);
  2606. GNUNET_free (mytemp);
  2607. GNUNET_free (arg);
  2608. return ret;
  2609. }
  2610. procarr[pg_iter] = NULL;
  2611. #if VERBOSE_TESTING
  2612. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  2613. "Copying file with command scp %s %s\n",
  2614. mytemp,
  2615. arg);
  2616. #endif
  2617. GNUNET_free (arg);
  2618. }
  2619. GNUNET_free (temp_service_path);
  2620. GNUNET_free (mytemp);
  2621. }
  2622. #if NOT_STUPID
  2623. count = 0;
  2624. ret = GNUNET_SYSERR;
  2625. while ((count < max_wait) && (ret != GNUNET_OK))
  2626. {
  2627. ret = GNUNET_OK;
  2628. for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
  2629. {
  2630. #if VERBOSE_TESTING
  2631. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  2632. "Checking copy status of file %d\n",
  2633. pg_iter);
  2634. #endif
  2635. if (procarr[pg_iter] != NULL) /* Check for already completed! */
  2636. {
  2637. if (GNUNET_OS_process_status
  2638. (procarr[pg_iter], &type, &return_code) != GNUNET_OK)
  2639. {
  2640. ret = GNUNET_SYSERR;
  2641. }
  2642. else if ((type != GNUNET_OS_PROCESS_EXITED)
  2643. || (return_code != 0))
  2644. {
  2645. ret = GNUNET_SYSERR;
  2646. }
  2647. else
  2648. {
  2649. GNUNET_OS_process_close (procarr[pg_iter]);
  2650. procarr[pg_iter] = NULL;
  2651. #if VERBOSE_TESTING
  2652. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  2653. "File %d copied\n",
  2654. pg_iter);
  2655. #endif
  2656. }
  2657. }
  2658. }
  2659. count++;
  2660. if (ret == GNUNET_SYSERR)
  2661. {
  2662. /* FIXME: why sleep here? -CG */
  2663. sleep (1);
  2664. }
  2665. }
  2666. #if VERBOSE_TESTING
  2667. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  2668. _("Finished copying all friend files!\n"));
  2669. #endif
  2670. #endif
  2671. GNUNET_free (procarr);
  2672. return ret;
  2673. }
  2674. /*
  2675. * Create the blacklist files based on the PeerConnection's
  2676. * of each peer in the peer group, and copy the files
  2677. * to the appropriate place.
  2678. *
  2679. * @param pg the peer group we are dealing with
  2680. * @param transports space delimited list of transports to blacklist
  2681. */
  2682. static int
  2683. create_and_copy_blacklist_files(struct GNUNET_TESTING_PeerGroup *pg,
  2684. const char *transports)
  2685. {
  2686. FILE *temp_file_handle;
  2687. unsigned int pg_iter;
  2688. char *temp_service_path;
  2689. struct GNUNET_OS_Process **procarr;
  2690. char *arg;
  2691. char *mytemp;
  2692. enum GNUNET_OS_ProcessStatusType type;
  2693. unsigned long return_code;
  2694. int count;
  2695. int ret;
  2696. int max_wait = 10;
  2697. int transport_len;
  2698. unsigned int i;
  2699. char *pos;
  2700. char *temp_transports;
  2701. #if OLD
  2702. struct GNUNET_CRYPTO_HashAsciiEncoded peer_enc;
  2703. struct PeerConnection *conn_iter;
  2704. #else
  2705. static struct BlacklistContext blacklist_ctx;
  2706. #endif
  2707. procarr = GNUNET_malloc (sizeof (struct GNUNET_OS_Process *) * pg->total);
  2708. for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
  2709. {
  2710. mytemp = GNUNET_DISK_mktemp ("blacklist");
  2711. GNUNET_assert (mytemp != NULL);
  2712. temp_file_handle = fopen (mytemp, "wt");
  2713. GNUNET_assert (temp_file_handle != NULL);
  2714. temp_transports = GNUNET_strdup (transports);
  2715. #if !OLD
  2716. blacklist_ctx.temp_file_handle = temp_file_handle;
  2717. #endif
  2718. transport_len = strlen (temp_transports) + 1;
  2719. pos = NULL;
  2720. for (i = 0; i < transport_len; i++)
  2721. {
  2722. if ((temp_transports[i] == ' ') && (pos == NULL))
  2723. continue; /* At start of string (whitespace) */
  2724. else if ((temp_transports[i] == ' ') || (temp_transports[i] == '\0')) /* At end of string */
  2725. {
  2726. temp_transports[i] = '\0';
  2727. #if OLD
  2728. conn_iter = pg->peers[pg_iter].blacklisted_peers_head;
  2729. while (conn_iter != NULL)
  2730. {
  2731. GNUNET_CRYPTO_hash_to_enc (
  2732. &pg->peers[conn_iter->index].daemon->id.hashPubKey,
  2733. &peer_enc);
  2734. fprintf (temp_file_handle, "%s:%s\n", pos, (char *) &peer_enc);
  2735. conn_iter = conn_iter->next;
  2736. }
  2737. #else
  2738. blacklist_ctx.transport = pos;
  2739. (void) GNUNET_CONTAINER_multihashmap_iterate (pg->
  2740. peers
  2741. [pg_iter].blacklisted_peers,
  2742. &blacklist_file_iterator,
  2743. &blacklist_ctx);
  2744. #endif
  2745. pos = NULL;
  2746. } /* At beginning of actual string */
  2747. else if (pos == NULL)
  2748. {
  2749. pos = &temp_transports[i];
  2750. }
  2751. }
  2752. GNUNET_free (temp_transports);
  2753. fclose (temp_file_handle);
  2754. if (GNUNET_OK
  2755. != GNUNET_CONFIGURATION_get_value_string (
  2756. pg->peers[pg_iter]. daemon->cfg,
  2757. "PATHS", "SERVICEHOME",
  2758. &temp_service_path))
  2759. {
  2760. GNUNET_log (
  2761. GNUNET_ERROR_TYPE_WARNING,
  2762. _
  2763. ("No `%s' specified in peer configuration in section `%s', cannot copy friends file!\n"),
  2764. "SERVICEHOME", "PATHS");
  2765. if (UNLINK (mytemp) != 0)
  2766. GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "unlink",
  2767. mytemp);
  2768. GNUNET_free (mytemp);
  2769. break;
  2770. }
  2771. if (pg->peers[pg_iter].daemon->hostname == NULL) /* Local, just copy the file */
  2772. {
  2773. GNUNET_asprintf (&arg, "%s/blacklist", temp_service_path);
  2774. procarr[pg_iter] = GNUNET_OS_start_process (NULL, NULL, "mv", "mv",
  2775. mytemp, arg, NULL);
  2776. #if VERBOSE_TESTING
  2777. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  2778. _("Copying file with command cp %s %s\n"), mytemp, arg);
  2779. #endif
  2780. GNUNET_free (arg);
  2781. }
  2782. else /* Remote, scp the file to the correct place */
  2783. {
  2784. if (NULL != pg->peers[pg_iter].daemon->username)
  2785. GNUNET_asprintf (&arg, "%s@%s:%s/blacklist",
  2786. pg->peers[pg_iter].daemon->username,
  2787. pg->peers[pg_iter].daemon->hostname,
  2788. temp_service_path);
  2789. else
  2790. GNUNET_asprintf (&arg, "%s:%s/blacklist",
  2791. pg->peers[pg_iter].daemon->hostname,
  2792. temp_service_path);
  2793. procarr[pg_iter] = GNUNET_OS_start_process (NULL, NULL, "scp", "scp",
  2794. mytemp, arg, NULL);
  2795. GNUNET_assert(procarr[pg_iter] != NULL);
  2796. GNUNET_OS_process_wait (procarr[pg_iter]); /* FIXME: add scheduled blacklist file copy that parallelizes file copying! */
  2797. #if VERBOSE_TESTING
  2798. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  2799. _("Copying file with command scp %s %s\n"), mytemp,
  2800. arg);
  2801. #endif
  2802. GNUNET_free (arg);
  2803. }
  2804. GNUNET_free (temp_service_path);
  2805. GNUNET_free (mytemp);
  2806. }
  2807. count = 0;
  2808. ret = GNUNET_SYSERR;
  2809. while ((count < max_wait) && (ret != GNUNET_OK))
  2810. {
  2811. ret = GNUNET_OK;
  2812. for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
  2813. {
  2814. #if VERBOSE_TESTING
  2815. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  2816. _("Checking copy status of file %d\n"), pg_iter);
  2817. #endif
  2818. if (procarr[pg_iter] != NULL) /* Check for already completed! */
  2819. {
  2820. if (GNUNET_OS_process_status (procarr[pg_iter], &type,
  2821. &return_code) != GNUNET_OK)
  2822. {
  2823. ret = GNUNET_SYSERR;
  2824. }
  2825. else if ((type != GNUNET_OS_PROCESS_EXITED) || (return_code != 0))
  2826. {
  2827. ret = GNUNET_SYSERR;
  2828. }
  2829. else
  2830. {
  2831. GNUNET_OS_process_close (procarr[pg_iter]);
  2832. procarr[pg_iter] = NULL;
  2833. #if VERBOSE_TESTING
  2834. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  2835. _("File %d copied\n"), pg_iter);
  2836. #endif
  2837. }
  2838. }
  2839. }
  2840. count++;
  2841. if (ret == GNUNET_SYSERR)
  2842. {
  2843. /* FIXME: why sleep here? -CG */
  2844. sleep (1);
  2845. }
  2846. }
  2847. #if VERBOSE_TESTING
  2848. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  2849. _("Finished copying all blacklist files!\n"));
  2850. #endif
  2851. GNUNET_free (procarr);
  2852. return ret;
  2853. }
  2854. /* Forward Declaration */
  2855. static void
  2856. schedule_connect(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
  2857. /**
  2858. * Choose a random peer's next connection to create, and
  2859. * call schedule_connect to set up the connect task.
  2860. *
  2861. * @param ct_ctx the overall connection context
  2862. */
  2863. static void
  2864. preschedule_connect(struct GNUNET_TESTING_PeerGroup *pg)
  2865. {
  2866. struct ConnectTopologyContext *ct_ctx = &pg->ct_ctx;
  2867. struct PeerConnection *connection_iter;
  2868. struct ConnectContext *connect_context;
  2869. uint32_t random_peer;
  2870. if (ct_ctx->remaining_connections == 0)
  2871. return;
  2872. random_peer
  2873. = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, pg->total);
  2874. while (pg->peers[random_peer].connect_peers_head == NULL)
  2875. random_peer = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
  2876. pg->total);
  2877. connection_iter = pg->peers[random_peer].connect_peers_head;
  2878. connect_context = GNUNET_malloc (sizeof (struct ConnectContext));
  2879. connect_context->first_index = random_peer;
  2880. connect_context->second_index = connection_iter->index;
  2881. connect_context->ct_ctx = ct_ctx;
  2882. GNUNET_SCHEDULER_add_now (&schedule_connect, connect_context);
  2883. GNUNET_CONTAINER_DLL_remove(pg->peers[random_peer].connect_peers_head, pg->peers[random_peer].connect_peers_tail, connection_iter);
  2884. GNUNET_free(connection_iter);
  2885. ct_ctx->remaining_connections--;
  2886. }
  2887. #if USE_SEND_HELLOS
  2888. /* Forward declaration */
  2889. static void schedule_send_hellos (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
  2890. /**
  2891. * Close connections and free the hello context.
  2892. *
  2893. * @param cls the 'struct SendHelloContext *'
  2894. * @param tc scheduler context
  2895. */
  2896. static void
  2897. free_hello_context (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
  2898. {
  2899. struct SendHelloContext *send_hello_context = cls;
  2900. if (send_hello_context->peer->daemon->server != NULL)
  2901. {
  2902. GNUNET_CORE_disconnect(send_hello_context->peer->daemon->server);
  2903. send_hello_context->peer->daemon->server = NULL;
  2904. }
  2905. if (send_hello_context->peer->daemon->th != NULL)
  2906. {
  2907. GNUNET_TRANSPORT_disconnect(send_hello_context->peer->daemon->th);
  2908. send_hello_context->peer->daemon->th = NULL;
  2909. }
  2910. if (send_hello_context->core_connect_task != GNUNET_SCHEDULER_NO_TASK)
  2911. {
  2912. GNUNET_SCHEDULER_cancel(send_hello_context->core_connect_task);
  2913. send_hello_context->core_connect_task = GNUNET_SCHEDULER_NO_TASK;
  2914. }
  2915. send_hello_context->pg->outstanding_connects--;
  2916. GNUNET_free(send_hello_context);
  2917. }
  2918. /**
  2919. * For peers that haven't yet connected, notify
  2920. * the caller that they have failed (timeout).
  2921. *
  2922. * @param cls the 'struct SendHelloContext *'
  2923. * @param tc scheduler context
  2924. */
  2925. static void
  2926. notify_remaining_connections_failed (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
  2927. {
  2928. struct SendHelloContext *send_hello_context = cls;
  2929. struct GNUNET_TESTING_PeerGroup *pg = send_hello_context->pg;
  2930. struct PeerConnection *connection;
  2931. GNUNET_CORE_disconnect(send_hello_context->peer->daemon->server);
  2932. send_hello_context->peer->daemon->server = NULL;
  2933. connection = send_hello_context->peer->connect_peers_head;
  2934. while (connection != NULL)
  2935. {
  2936. if (pg->notify_connection != NULL)
  2937. {
  2938. pg->notify_connection(pg->notify_connection_cls,
  2939. &send_hello_context->peer->daemon->id,
  2940. &pg->peers[connection->index].daemon->id,
  2941. 0, /* FIXME */
  2942. send_hello_context->peer->daemon->cfg,
  2943. pg->peers[connection->index].daemon->cfg,
  2944. send_hello_context->peer->daemon,
  2945. pg->peers[connection->index].daemon,
  2946. "Peers failed to connect (timeout)");
  2947. }
  2948. GNUNET_CONTAINER_DLL_remove(send_hello_context->peer->connect_peers_head, send_hello_context->peer->connect_peers_tail, connection);
  2949. GNUNET_free(connection);
  2950. connection = connection->next;
  2951. }
  2952. GNUNET_SCHEDULER_add_now(&free_hello_context, send_hello_context);
  2953. #if BAD
  2954. other_peer = &pg->peers[connection->index];
  2955. #endif
  2956. }
  2957. /**
  2958. * For peers that haven't yet connected, send
  2959. * CORE connect requests.
  2960. *
  2961. * @param cls the 'struct SendHelloContext *'
  2962. * @param tc scheduler context
  2963. */
  2964. static void
  2965. send_core_connect_requests (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
  2966. {
  2967. struct SendHelloContext *send_hello_context = cls;
  2968. struct PeerConnection *conn;
  2969. GNUNET_assert(send_hello_context->peer->daemon->server != NULL);
  2970. send_hello_context->core_connect_task = GNUNET_SCHEDULER_NO_TASK;
  2971. send_hello_context->connect_attempts++;
  2972. if (send_hello_context->connect_attempts < send_hello_context->pg->ct_ctx.connect_attempts)
  2973. {
  2974. conn = send_hello_context->peer->connect_peers_head;
  2975. while (conn != NULL)
  2976. {
  2977. GNUNET_CORE_peer_request_connect(send_hello_context->peer->daemon->server,
  2978. &send_hello_context->pg->peers[conn->index].daemon->id,
  2979. NULL,
  2980. NULL);
  2981. conn = conn->next;
  2982. }
  2983. send_hello_context->core_connect_task = GNUNET_SCHEDULER_add_delayed(GNUNET_TIME_relative_divide(send_hello_context->pg->ct_ctx.connect_timeout, send_hello_context->pg->ct_ctx.connect_attempts) ,
  2984. &send_core_connect_requests,
  2985. send_hello_context);
  2986. }
  2987. else
  2988. {
  2989. GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Timeout before all connections created, marking rest as failed!\n");
  2990. GNUNET_SCHEDULER_add_now(&notify_remaining_connections_failed, send_hello_context);
  2991. }
  2992. }
  2993. /**
  2994. * Success, connection is up. Signal client our success.
  2995. *
  2996. * @param cls our "struct SendHelloContext"
  2997. * @param peer identity of the peer that has connected
  2998. * @param atsi performance information
  2999. *
  3000. * FIXME: remove peers from BOTH lists, call notify twice, should
  3001. * double the speed of connections as long as the list iteration
  3002. * doesn't take too long!
  3003. */
  3004. static void
  3005. core_connect_notify (void *cls,
  3006. const struct GNUNET_PeerIdentity *peer,
  3007. const struct GNUNET_TRANSPORT_ATS_Information *atsi)
  3008. {
  3009. struct SendHelloContext *send_hello_context = cls;
  3010. struct PeerConnection *connection;
  3011. struct GNUNET_TESTING_PeerGroup *pg = send_hello_context->pg;
  3012. #if BAD
  3013. struct PeerData *other_peer;
  3014. #endif
  3015. #if DEBUG_TESTING
  3016. GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
  3017. "Connected peer %s to peer %s\n",
  3018. ctx->d1->shortname, GNUNET_i2s(peer));
  3019. #endif
  3020. if (0 == memcmp(&send_hello_context->peer->daemon->id, peer, sizeof(struct GNUNET_PeerIdentity)))
  3021. return;
  3022. connection = send_hello_context->peer->connect_peers_head;
  3023. #if BAD
  3024. other_peer = NULL;
  3025. #endif
  3026. while ((connection != NULL) &&
  3027. (0 != memcmp(&pg->peers[connection->index].daemon->id, peer, sizeof(struct GNUNET_PeerIdentity))))
  3028. {
  3029. connection = connection->next;
  3030. }
  3031. if (connection == NULL)
  3032. {
  3033. GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Connected peer %s to %s, not in list (no problem(?))\n", GNUNET_i2s(peer), send_hello_context->peer->daemon->shortname);
  3034. }
  3035. else
  3036. {
  3037. #if BAD
  3038. other_peer = &pg->peers[connection->index];
  3039. #endif
  3040. if (pg->notify_connection != NULL)
  3041. {
  3042. pg->notify_connection(pg->notify_connection_cls,
  3043. &send_hello_context->peer->daemon->id,
  3044. peer,
  3045. 0, /* FIXME */
  3046. send_hello_context->peer->daemon->cfg,
  3047. pg->peers[connection->index].daemon->cfg,
  3048. send_hello_context->peer->daemon,
  3049. pg->peers[connection->index].daemon,
  3050. NULL);
  3051. }
  3052. GNUNET_CONTAINER_DLL_remove(send_hello_context->peer->connect_peers_head, send_hello_context->peer->connect_peers_tail, connection);
  3053. GNUNET_free(connection);
  3054. }
  3055. #if BAD
  3056. /* Notify of reverse connection and remove from other peers list of outstanding */
  3057. if (other_peer != NULL)
  3058. {
  3059. connection = other_peer->connect_peers_head;
  3060. while ((connection != NULL) &&
  3061. (0 != memcmp(&send_hello_context->peer->daemon->id, &pg->peers[connection->index].daemon->id, sizeof(struct GNUNET_PeerIdentity))))
  3062. {
  3063. connection = connection->next;
  3064. }
  3065. if (connection != NULL)
  3066. {
  3067. if (pg->notify_connection != NULL)
  3068. {
  3069. pg->notify_connection(pg->notify_connection_cls,
  3070. peer,
  3071. &send_hello_context->peer->daemon->id,
  3072. 0, /* FIXME */
  3073. pg->peers[connection->index].daemon->cfg,
  3074. send_hello_context->peer->daemon->cfg,
  3075. pg->peers[connection->index].daemon,
  3076. send_hello_context->peer->daemon,
  3077. NULL);
  3078. }
  3079. GNUNET_CONTAINER_DLL_remove(other_peer->connect_peers_head, other_peer->connect_peers_tail, connection);
  3080. GNUNET_free(connection);
  3081. }
  3082. }
  3083. #endif
  3084. if (send_hello_context->peer->connect_peers_head == NULL)
  3085. {
  3086. GNUNET_SCHEDULER_add_now(&free_hello_context, send_hello_context);
  3087. }
  3088. }
  3089. /**
  3090. * Notify of a successful connection to the core service.
  3091. *
  3092. * @param cls a struct SendHelloContext *
  3093. * @param server handle to the core service
  3094. * @param my_identity the peer identity of this peer
  3095. * @param publicKey the public key of the peer
  3096. */
  3097. void
  3098. core_init (void *cls,
  3099. struct GNUNET_CORE_Handle * server,
  3100. const struct GNUNET_PeerIdentity *
  3101. my_identity,
  3102. const struct
  3103. GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *
  3104. publicKey)
  3105. {
  3106. struct SendHelloContext *send_hello_context = cls;
  3107. send_hello_context->core_ready = GNUNET_YES;
  3108. }
  3109. /**
  3110. * Function called once a hello has been sent
  3111. * to the transport, move on to the next one
  3112. * or go away forever.
  3113. *
  3114. * @param cls the 'struct SendHelloContext *'
  3115. * @param tc scheduler context
  3116. */
  3117. static void
  3118. hello_sent_callback (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
  3119. {
  3120. struct SendHelloContext *send_hello_context = cls;
  3121. //unsigned int pg_iter;
  3122. if ( (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
  3123. {
  3124. GNUNET_free(send_hello_context);
  3125. return;
  3126. }
  3127. send_hello_context->pg->remaining_hellos--;
  3128. #if DEBUG_TESTING
  3129. GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Sent HELLO, have %d remaining!\n", send_hello_context->pg->remaining_hellos);
  3130. #endif
  3131. if (send_hello_context->peer_pos == NULL) /* All HELLOs (for this peer!) have been transmitted! */
  3132. {
  3133. #if DEBUG_TESTING
  3134. GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "All hellos for this peer sent, disconnecting transport!\n");
  3135. #endif
  3136. GNUNET_assert(send_hello_context->peer->daemon->th != NULL);
  3137. GNUNET_TRANSPORT_disconnect(send_hello_context->peer->daemon->th);
  3138. send_hello_context->peer->daemon->th = NULL;
  3139. /*if (send_hello_context->pg->remaining_hellos == 0)
  3140. {
  3141. for (pg_iter = 0; pg_iter < send_hello_context->pg->max_outstanding_connections; pg_iter++)
  3142. {
  3143. preschedule_connect(&send_hello_context->pg->ct_ctx);
  3144. }
  3145. }
  3146. */
  3147. GNUNET_assert (send_hello_context->peer->daemon->server == NULL);
  3148. send_hello_context->peer->daemon->server = GNUNET_CORE_connect(send_hello_context->peer->cfg,
  3149. 1,
  3150. send_hello_context,
  3151. &core_init,
  3152. &core_connect_notify,
  3153. NULL,
  3154. NULL,
  3155. NULL, GNUNET_NO,
  3156. NULL, GNUNET_NO,
  3157. no_handlers);
  3158. send_hello_context->core_connect_task = GNUNET_SCHEDULER_add_delayed(GNUNET_TIME_relative_divide(send_hello_context->pg->ct_ctx.connect_timeout, send_hello_context->pg->ct_ctx.connect_attempts),
  3159. &send_core_connect_requests,
  3160. send_hello_context);
  3161. }
  3162. else
  3163. GNUNET_SCHEDULER_add_now(&schedule_send_hellos, send_hello_context);
  3164. }
  3165. /**
  3166. * Connect to a peer, give it all the HELLO's of those peers
  3167. * we will later ask it to connect to.
  3168. *
  3169. * @param ct_ctx the overall connection context
  3170. */
  3171. static void schedule_send_hellos (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
  3172. {
  3173. struct SendHelloContext *send_hello_context = cls;
  3174. struct GNUNET_TESTING_PeerGroup *pg = send_hello_context->pg;
  3175. if ( (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
  3176. {
  3177. GNUNET_free(send_hello_context);
  3178. return;
  3179. }
  3180. GNUNET_assert(send_hello_context->peer_pos != NULL); /* All of the HELLO sends to be scheduled have been scheduled! */
  3181. if (((send_hello_context->peer->daemon->th == NULL) &&
  3182. (pg->outstanding_connects > pg->max_outstanding_connections)) ||
  3183. (pg->stop_connects == GNUNET_YES))
  3184. {
  3185. #if VERBOSE_TESTING > 2
  3186. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  3187. _
  3188. ("Delaying connect, we have too many outstanding connections!\n"));
  3189. #endif
  3190. GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
  3191. (GNUNET_TIME_UNIT_MILLISECONDS, 100),
  3192. &schedule_send_hellos, send_hello_context);
  3193. }
  3194. else
  3195. {
  3196. #if VERBOSE_TESTING > 2
  3197. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  3198. _("Creating connection, outstanding_connections is %d\n"),
  3199. outstanding_connects);
  3200. #endif
  3201. if (send_hello_context->peer->daemon->th == NULL)
  3202. {
  3203. pg->outstanding_connects++; /* Actual TRANSPORT, CORE connections! */
  3204. send_hello_context->peer->daemon->th
  3205. = GNUNET_TRANSPORT_connect (send_hello_context->peer->cfg, NULL,
  3206. send_hello_context, NULL, NULL, NULL);
  3207. }
  3208. #if DEBUG_TESTING
  3209. GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
  3210. _("Offering Hello of peer %s to peer %s\n"),
  3211. send_hello_context->peer->daemon->shortname, pg->peers[send_hello_context->peer_pos->index].daemon->shortname);
  3212. #endif
  3213. GNUNET_TRANSPORT_offer_hello(send_hello_context->peer->daemon->th,
  3214. (const struct GNUNET_MessageHeader *)pg->peers[send_hello_context->peer_pos->index].daemon->hello,
  3215. &hello_sent_callback,
  3216. send_hello_context);
  3217. send_hello_context->peer_pos = send_hello_context->peer_pos->next;
  3218. GNUNET_assert(send_hello_context->peer->daemon->th != NULL);
  3219. }
  3220. }
  3221. #endif
  3222. /**
  3223. * Internal notification of a connection, kept so that we can ensure some connections
  3224. * happen instead of flooding all testing daemons with requests to connect.
  3225. */
  3226. static void
  3227. internal_connect_notify(void *cls, const struct GNUNET_PeerIdentity *first,
  3228. const struct GNUNET_PeerIdentity *second,
  3229. uint32_t distance,
  3230. const struct GNUNET_CONFIGURATION_Handle *first_cfg,
  3231. const struct GNUNET_CONFIGURATION_Handle *second_cfg,
  3232. struct GNUNET_TESTING_Daemon *first_daemon,
  3233. struct GNUNET_TESTING_Daemon *second_daemon,
  3234. const char *emsg)
  3235. {
  3236. struct ConnectContext *connect_ctx = cls;
  3237. struct ConnectTopologyContext *ct_ctx = connect_ctx->ct_ctx;
  3238. struct GNUNET_TESTING_PeerGroup *pg = ct_ctx->pg;
  3239. struct PeerConnection *connection;
  3240. GNUNET_assert (0 < pg->outstanding_connects);
  3241. pg->outstanding_connects--;
  3242. /*
  3243. * Check whether the inverse connection has been scheduled yet,
  3244. * if not, we can remove it from the other peers list and avoid
  3245. * even trying to connect them again!
  3246. */
  3247. connection = pg->peers[connect_ctx->second_index].connect_peers_head;
  3248. #if BAD
  3249. other_peer = NULL;
  3250. #endif
  3251. while ((connection != NULL) && (0
  3252. != memcmp (first, &pg->peers[connection->index].daemon->id,
  3253. sizeof(struct GNUNET_PeerIdentity))))
  3254. {
  3255. connection = connection->next;
  3256. }
  3257. if (connection != NULL) /* Can safely remove! */
  3258. {
  3259. GNUNET_assert (0 < ct_ctx->remaining_connections);
  3260. ct_ctx->remaining_connections--;
  3261. if (pg->notify_connection != NULL) /* Notify of reverse connection */
  3262. pg->notify_connection (pg->notify_connection_cls, second, first,
  3263. distance, second_cfg, first_cfg, second_daemon,
  3264. first_daemon, emsg);
  3265. GNUNET_CONTAINER_DLL_remove(pg->peers[connect_ctx->second_index].connect_peers_head, pg->peers[connect_ctx->second_index].connect_peers_tail, connection);
  3266. GNUNET_free(connection);
  3267. }
  3268. if (ct_ctx->remaining_connections == 0)
  3269. {
  3270. if (ct_ctx->notify_connections_done != NULL)
  3271. {
  3272. ct_ctx->notify_connections_done (ct_ctx->notify_cls, NULL);
  3273. ct_ctx->notify_connections_done = NULL;
  3274. }
  3275. }
  3276. else
  3277. preschedule_connect (pg);
  3278. if (pg->notify_connection != NULL)
  3279. pg->notify_connection (pg->notify_connection_cls, first, second, distance,
  3280. first_cfg, second_cfg, first_daemon, second_daemon,
  3281. emsg);
  3282. GNUNET_free(connect_ctx);
  3283. }
  3284. /**
  3285. * Either delay a connection (because there are too many outstanding)
  3286. * or schedule it for right now.
  3287. *
  3288. * @param cls a connection context
  3289. * @param tc the task runtime context
  3290. */
  3291. static void
  3292. schedule_connect(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
  3293. {
  3294. struct ConnectContext *connect_context = cls;
  3295. struct GNUNET_TESTING_PeerGroup *pg = connect_context->ct_ctx->pg;
  3296. if ( (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
  3297. return;
  3298. if ((pg->outstanding_connects > pg->max_outstanding_connections)
  3299. || (pg->stop_connects == GNUNET_YES))
  3300. {
  3301. #if VERBOSE_TESTING
  3302. GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
  3303. _
  3304. ("Delaying connect, we have too many outstanding connections!\n"));
  3305. #endif
  3306. GNUNET_SCHEDULER_add_delayed (
  3307. GNUNET_TIME_relative_multiply (
  3308. GNUNET_TIME_UNIT_MILLISECONDS,
  3309. 100),
  3310. &schedule_connect, connect_context);
  3311. }
  3312. else
  3313. {
  3314. #if VERBOSE_TESTING
  3315. GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
  3316. _("Creating connection, outstanding_connections is %d (max %d)\n"),
  3317. pg->outstanding_connects, pg->max_outstanding_connections);
  3318. #endif
  3319. pg->outstanding_connects++;
  3320. pg->total_connects_scheduled++;
  3321. GNUNET_TESTING_daemons_connect (
  3322. pg->peers[connect_context->first_index].daemon,
  3323. pg->peers[connect_context->second_index].daemon,
  3324. connect_context->ct_ctx->connect_timeout,
  3325. connect_context->ct_ctx->connect_attempts,
  3326. #if USE_SEND_HELLOS
  3327. GNUNET_NO,
  3328. #else
  3329. GNUNET_YES,
  3330. #endif
  3331. &internal_connect_notify, connect_context); /* FIXME: free connect context! */
  3332. }
  3333. }
  3334. #if !OLD
  3335. /**
  3336. * Iterator for actually scheduling connections to be created
  3337. * between two peers.
  3338. *
  3339. * @param cls closure, a GNUNET_TESTING_Daemon
  3340. * @param key the key the second Daemon was stored under
  3341. * @param value the GNUNET_TESTING_Daemon that the first is to connect to
  3342. *
  3343. * @return GNUNET_YES to continue iteration
  3344. */
  3345. static int
  3346. connect_iterator (void *cls, const GNUNET_HashCode * key, void *value)
  3347. {
  3348. struct ConnectTopologyContext *ct_ctx = cls;
  3349. struct PeerData *first = ct_ctx->first;
  3350. struct GNUNET_TESTING_Daemon *second = value;
  3351. struct ConnectContext *connect_context;
  3352. connect_context = GNUNET_malloc (sizeof (struct ConnectContext));
  3353. connect_context->first = first->daemon;
  3354. connect_context->second = second;
  3355. connect_context->ct_ctx = ct_ctx;
  3356. GNUNET_SCHEDULER_add_now (&schedule_connect, connect_context);
  3357. return GNUNET_YES;
  3358. }
  3359. #endif
  3360. #if !OLD
  3361. /**
  3362. * Iterator for copying all entries in the allowed hashmap to the
  3363. * connect hashmap.
  3364. *
  3365. * @param cls closure, a GNUNET_TESTING_Daemon
  3366. * @param key the key the second Daemon was stored under
  3367. * @param value the GNUNET_TESTING_Daemon that the first is to connect to
  3368. *
  3369. * @return GNUNET_YES to continue iteration
  3370. */
  3371. static int
  3372. copy_topology_iterator (void *cls, const GNUNET_HashCode * key, void *value)
  3373. {
  3374. struct PeerData *first = cls;
  3375. GNUNET_assert (GNUNET_OK ==
  3376. GNUNET_CONTAINER_multihashmap_put (first->connect_peers, key,
  3377. value,
  3378. GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
  3379. return GNUNET_YES;
  3380. }
  3381. #endif
  3382. /**
  3383. * Make the peers to connect the same as those that are allowed to be
  3384. * connected.
  3385. *
  3386. * @param pg the peer group
  3387. */
  3388. static int
  3389. copy_allowed_topology(struct GNUNET_TESTING_PeerGroup *pg)
  3390. {
  3391. unsigned int pg_iter;
  3392. int ret;
  3393. int total;
  3394. #if OLD
  3395. struct PeerConnection *iter;
  3396. #endif
  3397. total = 0;
  3398. ret = 0;
  3399. for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
  3400. {
  3401. #if OLD
  3402. iter = pg->peers[pg_iter].allowed_peers_head;
  3403. while (iter != NULL)
  3404. {
  3405. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  3406. "Creating connection between %d and %d\n", pg_iter,
  3407. iter->index);
  3408. total += add_connections (pg, pg_iter, iter->index, CONNECT,
  3409. GNUNET_YES);
  3410. //total += add_actual_connections(pg, pg_iter, iter->index);
  3411. iter = iter->next;
  3412. }
  3413. #else
  3414. ret =
  3415. GNUNET_CONTAINER_multihashmap_iterate (pg->
  3416. peers[pg_iter].allowed_peers,
  3417. &copy_topology_iterator,
  3418. &pg->peers[pg_iter]);
  3419. #endif
  3420. if (GNUNET_SYSERR == ret)
  3421. return GNUNET_SYSERR;
  3422. total = total + ret;
  3423. }
  3424. return total;
  3425. }
  3426. /**
  3427. * Connect the topology as specified by the PeerConnection's
  3428. * of each peer in the peer group
  3429. *
  3430. * @param pg the peer group we are dealing with
  3431. * @param connect_timeout how long try connecting two peers
  3432. * @param connect_attempts how many times (max) to attempt
  3433. * @param notify_callback callback to notify when finished
  3434. * @param notify_cls closure for notify callback
  3435. *
  3436. * @return the number of connections that will be attempted
  3437. */
  3438. static int
  3439. connect_topology(struct GNUNET_TESTING_PeerGroup *pg,
  3440. struct GNUNET_TIME_Relative connect_timeout,
  3441. unsigned int connect_attempts,
  3442. GNUNET_TESTING_NotifyCompletion notify_callback,
  3443. void *notify_cls)
  3444. {
  3445. unsigned int pg_iter;
  3446. unsigned int total;
  3447. #if OLD
  3448. struct PeerConnection *connection_iter;
  3449. #endif
  3450. #if USE_SEND_HELLOS
  3451. struct SendHelloContext *send_hello_context;
  3452. #endif
  3453. total = 0;
  3454. pg->ct_ctx.notify_connections_done = notify_callback;
  3455. pg->ct_ctx.notify_cls = notify_cls;
  3456. pg->ct_ctx.pg = pg;
  3457. for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
  3458. {
  3459. #if OLD
  3460. connection_iter = pg->peers[pg_iter].connect_peers_head;
  3461. while (connection_iter != NULL)
  3462. {
  3463. connection_iter = connection_iter->next;
  3464. total++;
  3465. }
  3466. #else
  3467. total +=
  3468. GNUNET_CONTAINER_multihashmap_size (pg->peers[pg_iter].connect_peers);
  3469. #endif
  3470. }
  3471. if (total == 0)
  3472. return total;
  3473. pg->ct_ctx.connect_timeout = connect_timeout;
  3474. pg->ct_ctx.connect_attempts = connect_attempts;
  3475. pg->ct_ctx.remaining_connections = total;
  3476. #if USE_SEND_HELLOS
  3477. /* First give all peers the HELLO's of other peers (connect to first peer's transport service, give HELLO's of other peers, continue...) */
  3478. pg->remaining_hellos = total;
  3479. for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
  3480. {
  3481. send_hello_context = GNUNET_malloc(sizeof(struct SendHelloContext));
  3482. send_hello_context->peer = &pg->peers[pg_iter];
  3483. send_hello_context->peer_pos = pg->peers[pg_iter].connect_peers_head;
  3484. send_hello_context->pg = pg;
  3485. GNUNET_SCHEDULER_add_now(&schedule_send_hellos, send_hello_context);
  3486. }
  3487. #else
  3488. for (pg_iter = 0; pg_iter < pg->max_outstanding_connections; pg_iter++)
  3489. {
  3490. preschedule_connect (pg);
  3491. }
  3492. #endif
  3493. return total;
  3494. }
  3495. /**
  3496. * Takes a peer group and creates a topology based on the
  3497. * one specified. Creates a topology means generates friend
  3498. * files for the peers so they can only connect to those allowed
  3499. * by the topology. This will only have an effect once peers
  3500. * are started if the FRIENDS_ONLY option is set in the base
  3501. * config. Also takes an optional restrict topology which
  3502. * disallows connections based on particular transports
  3503. * UNLESS they are specified in the restricted topology.
  3504. *
  3505. * @param pg the peer group struct representing the running peers
  3506. * @param topology which topology to connect the peers in
  3507. * @param restrict_topology disallow restrict_transports transport
  3508. * connections to peers NOT in this topology
  3509. * use GNUNET_TESTING_TOPOLOGY_NONE for no restrictions
  3510. * @param restrict_transports space delimited list of transports to blacklist
  3511. * to create restricted topology
  3512. *
  3513. * @return the maximum number of connections were all allowed peers
  3514. * connected to each other
  3515. */
  3516. unsigned int
  3517. GNUNET_TESTING_create_topology(struct GNUNET_TESTING_PeerGroup *pg,
  3518. enum GNUNET_TESTING_Topology topology,
  3519. enum GNUNET_TESTING_Topology restrict_topology,
  3520. const char *restrict_transports)
  3521. {
  3522. int ret;
  3523. unsigned int num_connections;
  3524. int unblacklisted_connections;
  3525. char *filename;
  3526. struct PeerConnection *conn_iter;
  3527. struct PeerConnection *temp_conn;
  3528. unsigned int off;
  3529. #if !OLD
  3530. unsigned int i;
  3531. for (i = 0; i < pg->total; i++)
  3532. {
  3533. pg->peers[i].allowed_peers =
  3534. GNUNET_CONTAINER_multihashmap_create (100);
  3535. pg->peers[i].connect_peers =
  3536. GNUNET_CONTAINER_multihashmap_create (100);
  3537. pg->peers[i].blacklisted_peers =
  3538. GNUNET_CONTAINER_multihashmap_create (100);
  3539. pg->peers[i].pg = pg;
  3540. }
  3541. #endif
  3542. switch (topology)
  3543. {
  3544. case GNUNET_TESTING_TOPOLOGY_CLIQUE:
  3545. #if VERBOSE_TESTING
  3546. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _("Creating clique topology\n"));
  3547. #endif
  3548. num_connections = create_clique (pg, &add_connections, ALLOWED, GNUNET_NO);
  3549. break;
  3550. case GNUNET_TESTING_TOPOLOGY_SMALL_WORLD_RING:
  3551. #if VERBOSE_TESTING
  3552. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  3553. _("Creating small world (ring) topology\n"));
  3554. #endif
  3555. num_connections = create_small_world_ring (pg, &add_connections, ALLOWED);
  3556. break;
  3557. case GNUNET_TESTING_TOPOLOGY_SMALL_WORLD:
  3558. #if VERBOSE_TESTING
  3559. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  3560. _("Creating small world (2d-torus) topology\n"));
  3561. #endif
  3562. num_connections = create_small_world (pg, &add_connections, ALLOWED);
  3563. break;
  3564. case GNUNET_TESTING_TOPOLOGY_RING:
  3565. #if VERBOSE_TESTING
  3566. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _("Creating ring topology\n"));
  3567. #endif
  3568. num_connections = create_ring (pg, &add_connections, ALLOWED);
  3569. break;
  3570. case GNUNET_TESTING_TOPOLOGY_2D_TORUS:
  3571. #if VERBOSE_TESTING
  3572. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _("Creating 2d torus topology\n"));
  3573. #endif
  3574. num_connections = create_2d_torus (pg, &add_connections, ALLOWED);
  3575. break;
  3576. case GNUNET_TESTING_TOPOLOGY_ERDOS_RENYI:
  3577. #if VERBOSE_TESTING
  3578. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  3579. _("Creating Erdos-Renyi topology\n"));
  3580. #endif
  3581. num_connections = create_erdos_renyi (pg, &add_connections, ALLOWED);
  3582. break;
  3583. case GNUNET_TESTING_TOPOLOGY_INTERNAT:
  3584. #if VERBOSE_TESTING
  3585. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _("Creating InterNAT topology\n"));
  3586. #endif
  3587. num_connections = create_nated_internet (pg, &add_connections, ALLOWED);
  3588. break;
  3589. case GNUNET_TESTING_TOPOLOGY_SCALE_FREE:
  3590. #if VERBOSE_TESTING
  3591. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  3592. _("Creating Scale Free topology\n"));
  3593. #endif
  3594. num_connections = create_scale_free (pg, &add_connections, ALLOWED);
  3595. break;
  3596. case GNUNET_TESTING_TOPOLOGY_LINE:
  3597. #if VERBOSE_TESTING
  3598. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  3599. _("Creating straight line topology\n"));
  3600. #endif
  3601. num_connections = create_line (pg, &add_connections, ALLOWED);
  3602. break;
  3603. case GNUNET_TESTING_TOPOLOGY_FROM_FILE:
  3604. #if VERBOSE_TESTING
  3605. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  3606. _("Creating topology from file!\n"));
  3607. #endif
  3608. if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (pg->cfg, "testing",
  3609. "topology_file",
  3610. &filename))
  3611. num_connections = create_from_file (pg, filename, &add_connections,
  3612. ALLOWED);
  3613. else
  3614. {
  3615. GNUNET_log (
  3616. GNUNET_ERROR_TYPE_WARNING,
  3617. "Missing configuration option TESTING:TOPOLOGY_FILE for creating topology from file!\n");
  3618. num_connections = 0;
  3619. }
  3620. break;
  3621. case GNUNET_TESTING_TOPOLOGY_NONE:
  3622. #if VERBOSE_TESTING
  3623. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  3624. _
  3625. ("Creating no allowed topology (all peers can connect at core level)\n"));
  3626. #endif
  3627. num_connections = pg->total * pg->total; /* Clique is allowed! */
  3628. break;
  3629. default:
  3630. num_connections = 0;
  3631. break;
  3632. }
  3633. if (GNUNET_YES == GNUNET_CONFIGURATION_get_value_yesno (pg->cfg, "TESTING",
  3634. "F2F"))
  3635. {
  3636. ret = create_and_copy_friend_files (pg);
  3637. if (ret != GNUNET_OK)
  3638. {
  3639. #if VERBOSE_TESTING
  3640. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  3641. _("Failed during friend file copying!\n"));
  3642. #endif
  3643. return GNUNET_SYSERR;
  3644. }
  3645. else
  3646. {
  3647. #if VERBOSE_TESTING
  3648. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  3649. _("Friend files created/copied successfully!\n"));
  3650. #endif
  3651. }
  3652. }
  3653. /* Use the create clique method to initially set all connections as blacklisted. */
  3654. if ((restrict_topology != GNUNET_TESTING_TOPOLOGY_NONE) && (restrict_topology
  3655. != GNUNET_TESTING_TOPOLOGY_FROM_FILE))
  3656. create_clique (pg, &add_connections, BLACKLIST, GNUNET_NO);
  3657. else
  3658. return num_connections;
  3659. unblacklisted_connections = 0;
  3660. /* Un-blacklist connections as per the topology specified */
  3661. switch (restrict_topology)
  3662. {
  3663. case GNUNET_TESTING_TOPOLOGY_CLIQUE:
  3664. #if VERBOSE_TESTING
  3665. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  3666. _("Blacklisting all but clique topology\n"));
  3667. #endif
  3668. unblacklisted_connections = create_clique (pg, &remove_connections,
  3669. BLACKLIST, GNUNET_NO);
  3670. break;
  3671. case GNUNET_TESTING_TOPOLOGY_SMALL_WORLD_RING:
  3672. #if VERBOSE_TESTING
  3673. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  3674. _("Blacklisting all but small world (ring) topology\n"));
  3675. #endif
  3676. unblacklisted_connections = create_small_world_ring (pg,
  3677. &remove_connections,
  3678. BLACKLIST);
  3679. break;
  3680. case GNUNET_TESTING_TOPOLOGY_SMALL_WORLD:
  3681. #if VERBOSE_TESTING
  3682. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  3683. _
  3684. ("Blacklisting all but small world (2d-torus) topology\n"));
  3685. #endif
  3686. unblacklisted_connections = create_small_world (pg, &remove_connections,
  3687. BLACKLIST);
  3688. break;
  3689. case GNUNET_TESTING_TOPOLOGY_RING:
  3690. #if VERBOSE_TESTING
  3691. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  3692. _("Blacklisting all but ring topology\n"));
  3693. #endif
  3694. unblacklisted_connections
  3695. = create_ring (pg, &remove_connections, BLACKLIST);
  3696. break;
  3697. case GNUNET_TESTING_TOPOLOGY_2D_TORUS:
  3698. #if VERBOSE_TESTING
  3699. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  3700. _("Blacklisting all but 2d torus topology\n"));
  3701. #endif
  3702. unblacklisted_connections = create_2d_torus (pg, &remove_connections,
  3703. BLACKLIST);
  3704. break;
  3705. case GNUNET_TESTING_TOPOLOGY_ERDOS_RENYI:
  3706. #if VERBOSE_TESTING
  3707. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  3708. _("Blacklisting all but Erdos-Renyi topology\n"));
  3709. #endif
  3710. unblacklisted_connections = create_erdos_renyi (pg, &remove_connections,
  3711. BLACKLIST);
  3712. break;
  3713. case GNUNET_TESTING_TOPOLOGY_INTERNAT:
  3714. #if VERBOSE_TESTING
  3715. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  3716. _("Blacklisting all but InterNAT topology\n"));
  3717. #endif
  3718. #if TOPOLOGY_HACK
  3719. for (off = 0; off < pg->total; off++)
  3720. {
  3721. conn_iter = pg->peers[off].allowed_peers_head;
  3722. while (conn_iter != NULL)
  3723. {
  3724. temp_conn = conn_iter->next;
  3725. GNUNET_free(conn_iter);
  3726. conn_iter = temp_conn;
  3727. }
  3728. pg->peers[off].allowed_peers_head = NULL;
  3729. pg->peers[off].allowed_peers_tail = NULL;
  3730. conn_iter = pg->peers[off].connect_peers_head;
  3731. while (conn_iter != NULL)
  3732. {
  3733. temp_conn = conn_iter->next;
  3734. GNUNET_free(conn_iter);
  3735. conn_iter = temp_conn;
  3736. }
  3737. pg->peers[off].connect_peers_head = NULL;
  3738. pg->peers[off].connect_peers_tail = NULL;
  3739. }
  3740. unblacklisted_connections
  3741. = create_nated_internet_copy (pg, &remove_connections, BLACKLIST);
  3742. #else
  3743. unblacklisted_connections =
  3744. create_nated_internet (pg, &remove_connections, BLACKLIST);
  3745. #endif
  3746. break;
  3747. case GNUNET_TESTING_TOPOLOGY_SCALE_FREE:
  3748. #if VERBOSE_TESTING
  3749. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  3750. _("Blacklisting all but Scale Free topology\n"));
  3751. #endif
  3752. unblacklisted_connections = create_scale_free (pg, &remove_connections,
  3753. BLACKLIST);
  3754. break;
  3755. case GNUNET_TESTING_TOPOLOGY_LINE:
  3756. #if VERBOSE_TESTING
  3757. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  3758. _("Blacklisting all but straight line topology\n"));
  3759. #endif
  3760. unblacklisted_connections
  3761. = create_line (pg, &remove_connections, BLACKLIST);
  3762. default:
  3763. break;
  3764. }
  3765. if ((unblacklisted_connections > 0) && (restrict_transports != NULL))
  3766. {
  3767. GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Creating blacklist with `%s'\n",
  3768. restrict_transports);
  3769. ret = create_and_copy_blacklist_files (pg, restrict_transports);
  3770. if (ret != GNUNET_OK)
  3771. {
  3772. #if VERBOSE_TESTING
  3773. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  3774. _("Failed during blacklist file copying!\n"));
  3775. #endif
  3776. return 0;
  3777. }
  3778. else
  3779. {
  3780. #if VERBOSE_TESTING
  3781. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  3782. _("Blacklist files created/copied successfully!\n"));
  3783. #endif
  3784. }
  3785. }
  3786. return num_connections;
  3787. }
  3788. #if !OLD
  3789. /**
  3790. * Iterator for choosing random peers to connect.
  3791. *
  3792. * @param cls closure, a RandomContext
  3793. * @param key the key the second Daemon was stored under
  3794. * @param value the GNUNET_TESTING_Daemon that the first is to connect to
  3795. *
  3796. * @return GNUNET_YES to continue iteration
  3797. */
  3798. static int
  3799. random_connect_iterator (void *cls, const GNUNET_HashCode * key, void *value)
  3800. {
  3801. struct RandomContext *random_ctx = cls;
  3802. double random_number;
  3803. uint32_t second_pos;
  3804. GNUNET_HashCode first_hash;
  3805. random_number =
  3806. ((double)
  3807. GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK,
  3808. UINT64_MAX)) / ((double) UINT64_MAX);
  3809. if (random_number < random_ctx->percentage)
  3810. {
  3811. GNUNET_assert (GNUNET_OK ==
  3812. GNUNET_CONTAINER_multihashmap_put (random_ctx->
  3813. first->connect_peers_working_set,
  3814. key, value,
  3815. GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
  3816. }
  3817. /* Now we have considered this particular connection, remove it from the second peer so it's not double counted */
  3818. uid_from_hash (key, &second_pos);
  3819. hash_from_uid (random_ctx->first_uid, &first_hash);
  3820. GNUNET_assert (random_ctx->pg->total > second_pos);
  3821. GNUNET_assert (GNUNET_YES ==
  3822. GNUNET_CONTAINER_multihashmap_remove (random_ctx->
  3823. pg->peers
  3824. [second_pos].connect_peers,
  3825. &first_hash,
  3826. random_ctx->
  3827. first->daemon));
  3828. return GNUNET_YES;
  3829. }
  3830. /**
  3831. * Iterator for adding at least X peers to a peers connection set.
  3832. *
  3833. * @param cls closure, MinimumContext
  3834. * @param key the key the second Daemon was stored under
  3835. * @param value the GNUNET_TESTING_Daemon that the first is to connect to
  3836. *
  3837. * @return GNUNET_YES to continue iteration
  3838. */
  3839. static int
  3840. minimum_connect_iterator (void *cls, const GNUNET_HashCode * key, void *value)
  3841. {
  3842. struct MinimumContext *min_ctx = cls;
  3843. uint32_t second_pos;
  3844. GNUNET_HashCode first_hash;
  3845. unsigned int i;
  3846. if (GNUNET_CONTAINER_multihashmap_size
  3847. (min_ctx->first->connect_peers_working_set) < min_ctx->num_to_add)
  3848. {
  3849. for (i = 0; i < min_ctx->num_to_add; i++)
  3850. {
  3851. if (min_ctx->pg_array[i] == min_ctx->current)
  3852. {
  3853. GNUNET_assert (GNUNET_OK ==
  3854. GNUNET_CONTAINER_multihashmap_put
  3855. (min_ctx->first->connect_peers_working_set, key,
  3856. value,
  3857. GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
  3858. uid_from_hash (key, &second_pos);
  3859. hash_from_uid (min_ctx->first_uid, &first_hash);
  3860. GNUNET_assert (min_ctx->pg->total > second_pos);
  3861. GNUNET_assert (GNUNET_OK ==
  3862. GNUNET_CONTAINER_multihashmap_put (min_ctx->
  3863. pg->peers
  3864. [second_pos].connect_peers_working_set,
  3865. &first_hash,
  3866. min_ctx->first->
  3867. daemon,
  3868. GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
  3869. /* Now we have added this particular connection, remove it from the second peer's map so it's not double counted */
  3870. GNUNET_assert (GNUNET_YES ==
  3871. GNUNET_CONTAINER_multihashmap_remove
  3872. (min_ctx->pg->peers[second_pos].connect_peers,
  3873. &first_hash, min_ctx->first->daemon));
  3874. }
  3875. }
  3876. min_ctx->current++;
  3877. return GNUNET_YES;
  3878. }
  3879. else
  3880. return GNUNET_NO; /* We can stop iterating, we have enough peers! */
  3881. }
  3882. /**
  3883. * Iterator for adding peers to a connection set based on a depth first search.
  3884. *
  3885. * @param cls closure, MinimumContext
  3886. * @param key the key the second daemon was stored under
  3887. * @param value the GNUNET_TESTING_Daemon that the first is to connect to
  3888. *
  3889. * @return GNUNET_YES to continue iteration
  3890. */
  3891. static int
  3892. dfs_connect_iterator (void *cls, const GNUNET_HashCode * key, void *value)
  3893. {
  3894. struct DFSContext *dfs_ctx = cls;
  3895. GNUNET_HashCode first_hash;
  3896. if (dfs_ctx->current == dfs_ctx->chosen)
  3897. {
  3898. GNUNET_assert (GNUNET_OK ==
  3899. GNUNET_CONTAINER_multihashmap_put (dfs_ctx->
  3900. first->connect_peers_working_set,
  3901. key, value,
  3902. GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
  3903. uid_from_hash (key, &dfs_ctx->second_uid);
  3904. hash_from_uid (dfs_ctx->first_uid, &first_hash);
  3905. GNUNET_assert (GNUNET_OK ==
  3906. GNUNET_CONTAINER_multihashmap_put (dfs_ctx->
  3907. pg->peers
  3908. [dfs_ctx->second_uid].connect_peers_working_set,
  3909. &first_hash,
  3910. dfs_ctx->
  3911. first->daemon,
  3912. GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
  3913. GNUNET_assert (GNUNET_YES ==
  3914. GNUNET_CONTAINER_multihashmap_remove (dfs_ctx->
  3915. pg->peers
  3916. [dfs_ctx->second_uid].connect_peers,
  3917. &first_hash,
  3918. dfs_ctx->
  3919. first->daemon));
  3920. /* Can't remove second from first yet because we are currently iterating, hence the return value in the DFSContext! */
  3921. return GNUNET_NO; /* We have found our peer, don't iterate more */
  3922. }
  3923. dfs_ctx->current++;
  3924. return GNUNET_YES;
  3925. }
  3926. #endif
  3927. /**
  3928. * From the set of connections possible, choose percentage percent of connections
  3929. * to actually connect.
  3930. *
  3931. * @param pg the peergroup we are dealing with
  3932. * @param percentage what percent of total connections to make
  3933. */
  3934. void
  3935. choose_random_connections(struct GNUNET_TESTING_PeerGroup *pg,
  3936. double percentage)
  3937. {
  3938. uint32_t pg_iter;
  3939. #if OLD
  3940. struct PeerConnection *conn_iter;
  3941. double random_number;
  3942. #else
  3943. struct RandomContext random_ctx;
  3944. #endif
  3945. for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
  3946. {
  3947. #if OLD
  3948. conn_iter = pg->peers[pg_iter].connect_peers_head;
  3949. while (conn_iter != NULL)
  3950. {
  3951. random_number
  3952. = ((double) GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK,
  3953. UINT64_MAX))
  3954. / ((double) UINT64_MAX);
  3955. if (random_number < percentage)
  3956. {
  3957. add_connections (pg, pg_iter, conn_iter->index, WORKING_SET,
  3958. GNUNET_YES);
  3959. }
  3960. conn_iter = conn_iter->next;
  3961. }
  3962. #else
  3963. random_ctx.first_uid = pg_iter;
  3964. random_ctx.first = &pg->peers[pg_iter];
  3965. random_ctx.percentage = percentage;
  3966. random_ctx.pg = pg;
  3967. pg->peers[pg_iter].connect_peers_working_set
  3968. = GNUNET_CONTAINER_multihashmap_create (pg->total);
  3969. GNUNET_CONTAINER_multihashmap_iterate (pg->peers[pg_iter].connect_peers,
  3970. &random_connect_iterator,
  3971. &random_ctx);
  3972. /* Now remove the old connections */
  3973. GNUNET_CONTAINER_multihashmap_destroy (pg->
  3974. peers[pg_iter].connect_peers);
  3975. /* And replace with the random set */
  3976. pg->peers[pg_iter].connect_peers
  3977. = pg->peers[pg_iter].connect_peers_working_set;
  3978. #endif
  3979. }
  3980. for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
  3981. {
  3982. conn_iter = pg->peers[pg_iter].connect_peers_head;
  3983. while (pg->peers[pg_iter].connect_peers_head != NULL)
  3984. remove_connections (pg, pg_iter,
  3985. pg->peers[pg_iter].connect_peers_head->index,
  3986. CONNECT, GNUNET_YES);
  3987. pg->peers[pg_iter].connect_peers_head
  3988. = pg->peers[pg_iter].connect_peers_working_set_head;
  3989. pg->peers[pg_iter].connect_peers_tail
  3990. = pg->peers[pg_iter].connect_peers_working_set_tail;
  3991. pg->peers[pg_iter].connect_peers_working_set_head = NULL;
  3992. pg->peers[pg_iter].connect_peers_working_set_tail = NULL;
  3993. }
  3994. }
  3995. /**
  3996. * Count the number of connections in a linked list of connections.
  3997. *
  3998. * @param conn_list the connection list to get the count of
  3999. *
  4000. * @return the number of elements in the list
  4001. */
  4002. static unsigned int
  4003. count_connections(struct PeerConnection *conn_list)
  4004. {
  4005. struct PeerConnection *iter;
  4006. unsigned int count;
  4007. count = 0;
  4008. iter = conn_list;
  4009. while (iter != NULL)
  4010. {
  4011. iter = iter->next;
  4012. count++;
  4013. }
  4014. return count;
  4015. }
  4016. static unsigned int
  4017. count_workingset_connections(struct GNUNET_TESTING_PeerGroup *pg)
  4018. {
  4019. unsigned int count;
  4020. unsigned int pg_iter;
  4021. #if OLD
  4022. struct PeerConnection *conn_iter;
  4023. #endif
  4024. count = 0;
  4025. for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
  4026. {
  4027. #if OLD
  4028. conn_iter = pg->peers[pg_iter].connect_peers_working_set_head;
  4029. while (conn_iter != NULL)
  4030. {
  4031. count++;
  4032. conn_iter = conn_iter->next;
  4033. }
  4034. #else
  4035. count +=
  4036. GNUNET_CONTAINER_multihashmap_size (pg->
  4037. peers
  4038. [pg_iter].connect_peers_working_set);
  4039. #endif
  4040. }
  4041. return count;
  4042. }
  4043. static unsigned int
  4044. count_allowed_connections(struct GNUNET_TESTING_PeerGroup *pg)
  4045. {
  4046. unsigned int count;
  4047. unsigned int pg_iter;
  4048. #if OLD
  4049. struct PeerConnection *conn_iter;
  4050. #endif
  4051. count = 0;
  4052. for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
  4053. {
  4054. #if OLD
  4055. conn_iter = pg->peers[pg_iter].allowed_peers_head;
  4056. while (conn_iter != NULL)
  4057. {
  4058. count++;
  4059. conn_iter = conn_iter->next;
  4060. }
  4061. #else
  4062. count +=
  4063. GNUNET_CONTAINER_multihashmap_size (pg->
  4064. peers
  4065. [pg_iter].allowed_peers);
  4066. #endif
  4067. }
  4068. return count;
  4069. }
  4070. /**
  4071. * From the set of connections possible, choose at least num connections per
  4072. * peer.
  4073. *
  4074. * @param pg the peergroup we are dealing with
  4075. * @param num how many connections at least should each peer have (if possible)?
  4076. */
  4077. static void
  4078. choose_minimum(struct GNUNET_TESTING_PeerGroup *pg, unsigned int num)
  4079. {
  4080. #if !OLD
  4081. struct MinimumContext minimum_ctx;
  4082. #else
  4083. struct PeerConnection *conn_iter;
  4084. unsigned int temp_list_size;
  4085. unsigned int i;
  4086. unsigned int count;
  4087. uint32_t random; /* Random list entry to connect peer to */
  4088. #endif
  4089. uint32_t pg_iter;
  4090. #if OLD
  4091. for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
  4092. {
  4093. temp_list_size
  4094. = count_connections (pg->peers[pg_iter].connect_peers_head);
  4095. if (temp_list_size == 0)
  4096. {
  4097. GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
  4098. "Peer %d has 0 connections!?!?\n", pg_iter);
  4099. break;
  4100. }
  4101. for (i = 0; i < num; i++)
  4102. {
  4103. random = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
  4104. temp_list_size);
  4105. conn_iter = pg->peers[pg_iter].connect_peers_head;
  4106. for (count = 0; count < random; count++)
  4107. conn_iter = conn_iter->next;
  4108. /* We now have a random connection, connect it! */
  4109. GNUNET_assert(conn_iter != NULL);
  4110. add_connections (pg, pg_iter, conn_iter->index, WORKING_SET,
  4111. GNUNET_YES);
  4112. }
  4113. }
  4114. #else
  4115. for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
  4116. {
  4117. pg->peers[pg_iter].connect_peers_working_set =
  4118. GNUNET_CONTAINER_multihashmap_create (num);
  4119. }
  4120. for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
  4121. {
  4122. minimum_ctx.first_uid = pg_iter;
  4123. minimum_ctx.pg_array =
  4124. GNUNET_CRYPTO_random_permute (GNUNET_CRYPTO_QUALITY_WEAK,
  4125. GNUNET_CONTAINER_multihashmap_size
  4126. (pg->peers[pg_iter].connect_peers));
  4127. minimum_ctx.first = &pg->peers[pg_iter];
  4128. minimum_ctx.pg = pg;
  4129. minimum_ctx.num_to_add = num;
  4130. minimum_ctx.current = 0;
  4131. GNUNET_CONTAINER_multihashmap_iterate (pg->peers[pg_iter].connect_peers,
  4132. &minimum_connect_iterator,
  4133. &minimum_ctx);
  4134. }
  4135. for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
  4136. {
  4137. /* Remove the "old" connections */
  4138. GNUNET_CONTAINER_multihashmap_destroy (pg->
  4139. peers[pg_iter].connect_peers);
  4140. /* And replace with the working set */
  4141. pg->peers[pg_iter].connect_peers =
  4142. pg->peers[pg_iter].connect_peers_working_set;
  4143. }
  4144. #endif
  4145. for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
  4146. {
  4147. while (pg->peers[pg_iter].connect_peers_head != NULL)
  4148. {
  4149. conn_iter = pg->peers[pg_iter].connect_peers_head;
  4150. GNUNET_CONTAINER_DLL_remove(pg->peers[pg_iter].connect_peers_head,
  4151. pg->peers[pg_iter].connect_peers_tail,
  4152. conn_iter);
  4153. GNUNET_free(conn_iter);
  4154. /*remove_connections(pg, pg_iter, pg->peers[pg_iter].connect_peers_head->index, CONNECT, GNUNET_YES);*/
  4155. }
  4156. pg->peers[pg_iter].connect_peers_head
  4157. = pg->peers[pg_iter].connect_peers_working_set_head;
  4158. pg->peers[pg_iter].connect_peers_tail
  4159. = pg->peers[pg_iter].connect_peers_working_set_tail;
  4160. pg->peers[pg_iter].connect_peers_working_set_head = NULL;
  4161. pg->peers[pg_iter].connect_peers_working_set_tail = NULL;
  4162. }
  4163. }
  4164. #if !OLD
  4165. struct FindClosestContext
  4166. {
  4167. /**
  4168. * The currently known closest peer.
  4169. */
  4170. struct GNUNET_TESTING_Daemon *closest;
  4171. /**
  4172. * The info for the peer we are adding connections for.
  4173. */
  4174. struct PeerData *curr_peer;
  4175. /**
  4176. * The distance (bits) between the current
  4177. * peer and the currently known closest.
  4178. */
  4179. unsigned int closest_dist;
  4180. /**
  4181. * The offset of the closest known peer in
  4182. * the peer group.
  4183. */
  4184. unsigned int closest_num;
  4185. };
  4186. /**
  4187. * Iterator over hash map entries of the allowed
  4188. * peer connections. Find the closest, not already
  4189. * connected peer and return it.
  4190. *
  4191. * @param cls closure (struct FindClosestContext)
  4192. * @param key current key code (hash of offset in pg)
  4193. * @param value value in the hash map - a GNUNET_TESTING_Daemon
  4194. * @return GNUNET_YES if we should continue to
  4195. * iterate,
  4196. * GNUNET_NO if not.
  4197. */
  4198. static int
  4199. find_closest_peers (void *cls, const GNUNET_HashCode * key, void *value)
  4200. {
  4201. struct FindClosestContext *closest_ctx = cls;
  4202. struct GNUNET_TESTING_Daemon *daemon = value;
  4203. if (((closest_ctx->closest == NULL) ||
  4204. (GNUNET_CRYPTO_hash_matching_bits
  4205. (&daemon->id.hashPubKey,
  4206. &closest_ctx->curr_peer->daemon->id.hashPubKey) >
  4207. closest_ctx->closest_dist))
  4208. && (GNUNET_YES !=
  4209. GNUNET_CONTAINER_multihashmap_contains (closest_ctx->
  4210. curr_peer->connect_peers,
  4211. key)))
  4212. {
  4213. closest_ctx->closest_dist =
  4214. GNUNET_CRYPTO_hash_matching_bits (&daemon->id.hashPubKey,
  4215. &closest_ctx->curr_peer->daemon->
  4216. id.hashPubKey);
  4217. closest_ctx->closest = daemon;
  4218. uid_from_hash (key, &closest_ctx->closest_num);
  4219. }
  4220. return GNUNET_YES;
  4221. }
  4222. /**
  4223. * From the set of connections possible, choose at num connections per
  4224. * peer based on depth which are closest out of those allowed. Guaranteed
  4225. * to add num peers to connect to, provided there are that many peers
  4226. * in the underlay topology to connect to.
  4227. *
  4228. * @param pg the peergroup we are dealing with
  4229. * @param num how many connections at least should each peer have (if possible)?
  4230. * @param proc processor to actually add the connections
  4231. * @param list the peer list to use
  4232. */
  4233. void
  4234. add_closest (struct GNUNET_TESTING_PeerGroup *pg, unsigned int num,
  4235. GNUNET_TESTING_ConnectionProcessor proc, enum PeerLists list)
  4236. {
  4237. #if OLD
  4238. #else
  4239. struct FindClosestContext closest_ctx;
  4240. #endif
  4241. uint32_t pg_iter;
  4242. uint32_t i;
  4243. for (i = 0; i < num; i++) /* Each time find a closest peer (from those available) */
  4244. {
  4245. for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
  4246. {
  4247. closest_ctx.curr_peer = &pg->peers[pg_iter];
  4248. closest_ctx.closest = NULL;
  4249. closest_ctx.closest_dist = 0;
  4250. closest_ctx.closest_num = 0;
  4251. GNUNET_CONTAINER_multihashmap_iterate (pg->
  4252. peers[pg_iter].allowed_peers,
  4253. &find_closest_peers,
  4254. &closest_ctx);
  4255. if (closest_ctx.closest != NULL)
  4256. {
  4257. GNUNET_assert (closest_ctx.closest_num < pg->total);
  4258. proc (pg, pg_iter, closest_ctx.closest_num, list);
  4259. }
  4260. }
  4261. }
  4262. }
  4263. #endif
  4264. /**
  4265. * From the set of connections possible, choose at least num connections per
  4266. * peer based on depth first traversal of peer connections. If DFS leaves
  4267. * peers unconnected, ensure those peers get connections.
  4268. *
  4269. * @param pg the peergroup we are dealing with
  4270. * @param num how many connections at least should each peer have (if possible)?
  4271. */
  4272. void
  4273. perform_dfs(struct GNUNET_TESTING_PeerGroup *pg, unsigned int num)
  4274. {
  4275. uint32_t pg_iter;
  4276. uint32_t dfs_count;
  4277. uint32_t starting_peer;
  4278. uint32_t least_connections;
  4279. uint32_t random_connection;
  4280. #if OLD
  4281. unsigned int temp_count;
  4282. struct PeerConnection *peer_iter;
  4283. #else
  4284. struct DFSContext dfs_ctx;
  4285. GNUNET_HashCode second_hash;
  4286. #endif
  4287. #if OLD
  4288. starting_peer = 0;
  4289. dfs_count = 0;
  4290. while ((count_workingset_connections (pg) < num * pg->total)
  4291. && (count_allowed_connections (pg) > 0))
  4292. {
  4293. if (dfs_count % pg->total == 0) /* Restart the DFS at some weakly connected peer */
  4294. {
  4295. least_connections = -1; /* Set to very high number */
  4296. for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
  4297. {
  4298. temp_count
  4299. = count_connections (
  4300. pg->peers[pg_iter].connect_peers_working_set_head);
  4301. if (temp_count < least_connections)
  4302. {
  4303. starting_peer = pg_iter;
  4304. least_connections = temp_count;
  4305. }
  4306. }
  4307. }
  4308. temp_count
  4309. = count_connections (pg->peers[starting_peer].connect_peers_head);
  4310. if (temp_count == 0)
  4311. continue; /* FIXME: infinite loop? */
  4312. random_connection = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
  4313. temp_count);
  4314. temp_count = 0;
  4315. peer_iter = pg->peers[starting_peer].connect_peers_head;
  4316. while (temp_count < random_connection)
  4317. {
  4318. peer_iter = peer_iter->next;
  4319. temp_count++;
  4320. }
  4321. GNUNET_assert(peer_iter != NULL);
  4322. add_connections (pg, starting_peer, peer_iter->index, WORKING_SET,
  4323. GNUNET_NO);
  4324. remove_connections (pg, starting_peer, peer_iter->index, CONNECT,
  4325. GNUNET_YES);
  4326. starting_peer = peer_iter->index;
  4327. dfs_count++;
  4328. }
  4329. #else
  4330. for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
  4331. {
  4332. pg->peers[pg_iter].connect_peers_working_set =
  4333. GNUNET_CONTAINER_multihashmap_create (num);
  4334. }
  4335. starting_peer = 0;
  4336. dfs_count = 0;
  4337. while ((count_workingset_connections (pg) < num * pg->total)
  4338. && (count_allowed_connections (pg) > 0))
  4339. {
  4340. if (dfs_count % pg->total == 0) /* Restart the DFS at some weakly connected peer */
  4341. {
  4342. least_connections = -1; /* Set to very high number */
  4343. for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
  4344. {
  4345. if (GNUNET_CONTAINER_multihashmap_size
  4346. (pg->peers[pg_iter].connect_peers_working_set) <
  4347. least_connections)
  4348. {
  4349. starting_peer = pg_iter;
  4350. least_connections =
  4351. GNUNET_CONTAINER_multihashmap_size (pg->
  4352. peers
  4353. [pg_iter].connect_peers_working_set);
  4354. }
  4355. }
  4356. }
  4357. if (GNUNET_CONTAINER_multihashmap_size (pg->peers[starting_peer].connect_peers) == 0) /* Ensure there is at least one peer left to connect! */
  4358. {
  4359. dfs_count = 0;
  4360. continue;
  4361. }
  4362. /* Choose a random peer from the chosen peers set of connections to add */
  4363. dfs_ctx.chosen =
  4364. GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
  4365. GNUNET_CONTAINER_multihashmap_size
  4366. (pg->peers[starting_peer].connect_peers));
  4367. dfs_ctx.first_uid = starting_peer;
  4368. dfs_ctx.first = &pg->peers[starting_peer];
  4369. dfs_ctx.pg = pg;
  4370. dfs_ctx.current = 0;
  4371. GNUNET_CONTAINER_multihashmap_iterate (pg->
  4372. peers
  4373. [starting_peer].connect_peers,
  4374. &dfs_connect_iterator, &dfs_ctx);
  4375. /* Remove the second from the first, since we will be continuing the search and may encounter the first peer again! */
  4376. hash_from_uid (dfs_ctx.second_uid, &second_hash);
  4377. GNUNET_assert (GNUNET_YES ==
  4378. GNUNET_CONTAINER_multihashmap_remove (pg->peers
  4379. [starting_peer].connect_peers,
  4380. &second_hash,
  4381. pg->
  4382. peers
  4383. [dfs_ctx.second_uid].daemon));
  4384. starting_peer = dfs_ctx.second_uid;
  4385. }
  4386. for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
  4387. {
  4388. /* Remove the "old" connections */
  4389. GNUNET_CONTAINER_multihashmap_destroy (pg->
  4390. peers[pg_iter].connect_peers);
  4391. /* And replace with the working set */
  4392. pg->peers[pg_iter].connect_peers =
  4393. pg->peers[pg_iter].connect_peers_working_set;
  4394. }
  4395. #endif
  4396. }
  4397. /**
  4398. * Internal callback for topology information for a particular peer.
  4399. */
  4400. static void
  4401. internal_topology_callback(void *cls, const struct GNUNET_PeerIdentity *peer,
  4402. const struct GNUNET_TRANSPORT_ATS_Information *atsi)
  4403. {
  4404. struct CoreContext *core_ctx = cls;
  4405. struct TopologyIterateContext *iter_ctx = core_ctx->iter_context;
  4406. if (peer == NULL) /* Either finished, or something went wrong */
  4407. {
  4408. iter_ctx->completed++;
  4409. iter_ctx->connected--;
  4410. /* One core context allocated per iteration, must free! */
  4411. GNUNET_free (core_ctx);
  4412. }
  4413. else
  4414. {
  4415. iter_ctx->topology_cb (iter_ctx->cls, &core_ctx->daemon->id, peer, NULL);
  4416. }
  4417. if (iter_ctx->completed == iter_ctx->total)
  4418. {
  4419. iter_ctx->topology_cb (iter_ctx->cls, NULL, NULL, NULL);
  4420. /* Once all are done, free the iteration context */
  4421. GNUNET_free (iter_ctx);
  4422. }
  4423. }
  4424. /**
  4425. * Check running topology iteration tasks, if below max start a new one, otherwise
  4426. * schedule for some time in the future.
  4427. */
  4428. static void
  4429. schedule_get_topology(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
  4430. {
  4431. struct CoreContext *core_context = cls;
  4432. struct TopologyIterateContext *topology_context =
  4433. (struct TopologyIterateContext *) core_context->iter_context;
  4434. if ( (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
  4435. return;
  4436. if (topology_context->connected
  4437. > topology_context->pg->max_outstanding_connections)
  4438. {
  4439. #if VERBOSE_TESTING > 2
  4440. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  4441. _
  4442. ("Delaying connect, we have too many outstanding connections!\n"));
  4443. #endif
  4444. GNUNET_SCHEDULER_add_delayed (
  4445. GNUNET_TIME_relative_multiply (
  4446. GNUNET_TIME_UNIT_MILLISECONDS,
  4447. 100),
  4448. &schedule_get_topology, core_context);
  4449. }
  4450. else
  4451. {
  4452. #if VERBOSE_TESTING > 2
  4453. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  4454. _("Creating connection, outstanding_connections is %d\n"),
  4455. outstanding_connects);
  4456. #endif
  4457. topology_context->connected++;
  4458. if (GNUNET_OK != GNUNET_CORE_iterate_peers (core_context->daemon->cfg,
  4459. &internal_topology_callback,
  4460. core_context))
  4461. {
  4462. GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Topology iteration failed.\n");
  4463. internal_topology_callback (core_context, NULL, NULL);
  4464. }
  4465. }
  4466. }
  4467. /**
  4468. * Iterate over all (running) peers in the peer group, retrieve
  4469. * all connections that each currently has.
  4470. */
  4471. void
  4472. GNUNET_TESTING_get_topology(struct GNUNET_TESTING_PeerGroup *pg,
  4473. GNUNET_TESTING_NotifyTopology cb, void *cls)
  4474. {
  4475. struct TopologyIterateContext *topology_context;
  4476. struct CoreContext *core_ctx;
  4477. unsigned int i;
  4478. unsigned int total_count;
  4479. /* Allocate a single topology iteration context */
  4480. topology_context = GNUNET_malloc (sizeof (struct TopologyIterateContext));
  4481. topology_context->topology_cb = cb;
  4482. topology_context->cls = cls;
  4483. topology_context->pg = pg;
  4484. total_count = 0;
  4485. for (i = 0; i < pg->total; i++)
  4486. {
  4487. if (pg->peers[i].daemon->running == GNUNET_YES)
  4488. {
  4489. /* Allocate one core context per core we need to connect to */
  4490. core_ctx = GNUNET_malloc (sizeof (struct CoreContext));
  4491. core_ctx->daemon = pg->peers[i].daemon;
  4492. /* Set back pointer to topology iteration context */
  4493. core_ctx->iter_context = topology_context;
  4494. GNUNET_SCHEDULER_add_now (&schedule_get_topology, core_ctx);
  4495. total_count++;
  4496. }
  4497. }
  4498. if (total_count == 0)
  4499. {
  4500. cb (cls, NULL, NULL, "Cannot iterate over topology, no running peers!");
  4501. GNUNET_free (topology_context);
  4502. }
  4503. else
  4504. topology_context->total = total_count;
  4505. return;
  4506. }
  4507. /**
  4508. * Callback function to process statistic values.
  4509. * This handler is here only really to insert a peer
  4510. * identity (or daemon) so the statistics can be uniquely
  4511. * tied to a single running peer.
  4512. *
  4513. * @param cls closure
  4514. * @param subsystem name of subsystem that created the statistic
  4515. * @param name the name of the datum
  4516. * @param value the current value
  4517. * @param is_persistent GNUNET_YES if the value is persistent, GNUNET_NO if not
  4518. * @return GNUNET_OK to continue, GNUNET_SYSERR to abort iteration
  4519. */
  4520. static int
  4521. internal_stats_callback(void *cls, const char *subsystem, const char *name,
  4522. uint64_t value, int is_persistent)
  4523. {
  4524. struct StatsCoreContext *core_context = cls;
  4525. struct StatsIterateContext *stats_context =
  4526. (struct StatsIterateContext *) core_context->iter_context;
  4527. return stats_context->proc (stats_context->cls, &core_context->daemon->id,
  4528. subsystem, name, value, is_persistent);
  4529. }
  4530. /**
  4531. * Internal continuation call for statistics iteration.
  4532. *
  4533. * @param cls closure, the CoreContext for this iteration
  4534. * @param success whether or not the statistics iterations
  4535. * was canceled or not (we don't care)
  4536. */
  4537. static void
  4538. internal_stats_cont(void *cls, int success)
  4539. {
  4540. struct StatsCoreContext *core_context = cls;
  4541. struct StatsIterateContext *stats_context =
  4542. (struct StatsIterateContext *) core_context->iter_context;
  4543. stats_context->connected--;
  4544. stats_context->completed++;
  4545. if (stats_context->completed == stats_context->total)
  4546. {
  4547. stats_context->cont (stats_context->cls, GNUNET_YES);
  4548. GNUNET_free (stats_context);
  4549. }
  4550. if (core_context->stats_handle != NULL)
  4551. GNUNET_STATISTICS_destroy (core_context->stats_handle, GNUNET_NO);
  4552. GNUNET_free (core_context);
  4553. }
  4554. /**
  4555. * Check running topology iteration tasks, if below max start a new one, otherwise
  4556. * schedule for some time in the future.
  4557. */
  4558. static void
  4559. schedule_get_statistics(void *cls,
  4560. const struct GNUNET_SCHEDULER_TaskContext *tc)
  4561. {
  4562. struct StatsCoreContext *core_context = cls;
  4563. struct StatsIterateContext *stats_context =
  4564. (struct StatsIterateContext *) core_context->iter_context;
  4565. if ( (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
  4566. return;
  4567. if (stats_context->connected > stats_context->pg->max_outstanding_connections)
  4568. {
  4569. #if VERBOSE_TESTING > 2
  4570. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  4571. _
  4572. ("Delaying connect, we have too many outstanding connections!\n"));
  4573. #endif
  4574. GNUNET_SCHEDULER_add_delayed (
  4575. GNUNET_TIME_relative_multiply (
  4576. GNUNET_TIME_UNIT_MILLISECONDS,
  4577. 100),
  4578. &schedule_get_statistics, core_context);
  4579. }
  4580. else
  4581. {
  4582. #if VERBOSE_TESTING > 2
  4583. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  4584. _("Creating connection, outstanding_connections is %d\n"),
  4585. outstanding_connects);
  4586. #endif
  4587. stats_context->connected++;
  4588. core_context->stats_handle
  4589. = GNUNET_STATISTICS_create ("testing", core_context->daemon->cfg);
  4590. if (core_context->stats_handle == NULL)
  4591. {
  4592. internal_stats_cont (core_context, GNUNET_NO);
  4593. return;
  4594. }
  4595. core_context->stats_get_handle
  4596. = GNUNET_STATISTICS_get (core_context->stats_handle, NULL, NULL,
  4597. GNUNET_TIME_relative_get_forever (),
  4598. &internal_stats_cont,
  4599. &internal_stats_callback, core_context);
  4600. if (core_context->stats_get_handle == NULL)
  4601. internal_stats_cont (core_context, GNUNET_NO);
  4602. }
  4603. }
  4604. struct DuplicateStats
  4605. {
  4606. /**
  4607. * Next item in the list
  4608. */
  4609. struct DuplicateStats *next;
  4610. /**
  4611. * Nasty string, concatenation of relevant information.
  4612. */
  4613. char *unique_string;
  4614. };
  4615. /**
  4616. * Check whether the combination of port/host/unix domain socket
  4617. * already exists in the list of peers being checked for statistics.
  4618. *
  4619. * @param pg the peergroup in question
  4620. * @param specific_peer the peer we're concerned with
  4621. * @param stats_list the list to return to the caller
  4622. *
  4623. * @return GNUNET_YES if the statistics instance has been seen already,
  4624. * GNUNET_NO if not (and we may have added it to the list)
  4625. */
  4626. static int
  4627. stats_check_existing(struct GNUNET_TESTING_PeerGroup *pg,
  4628. struct PeerData *specific_peer,
  4629. struct DuplicateStats **stats_list)
  4630. {
  4631. struct DuplicateStats *pos;
  4632. char *unix_domain_socket;
  4633. unsigned long long port;
  4634. char *to_match;
  4635. if (GNUNET_YES
  4636. != GNUNET_CONFIGURATION_get_value_yesno (pg->cfg, "testing",
  4637. "single_statistics_per_host"))
  4638. return GNUNET_NO; /* Each peer has its own statistics instance, do nothing! */
  4639. pos = *stats_list;
  4640. if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (specific_peer->cfg,
  4641. "statistics",
  4642. "unixpath",
  4643. &unix_domain_socket))
  4644. return GNUNET_NO;
  4645. if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (specific_peer->cfg,
  4646. "statistics", "port",
  4647. &port))
  4648. {
  4649. GNUNET_free(unix_domain_socket);
  4650. return GNUNET_NO;
  4651. }
  4652. if (specific_peer->daemon->hostname != NULL)
  4653. GNUNET_asprintf (&to_match, "%s%s%llu", specific_peer->daemon->hostname,
  4654. unix_domain_socket, port);
  4655. else
  4656. GNUNET_asprintf (&to_match, "%s%llu", unix_domain_socket, port);
  4657. while (pos != NULL)
  4658. {
  4659. if (0 == strcmp (to_match, pos->unique_string))
  4660. {
  4661. GNUNET_free (unix_domain_socket);
  4662. GNUNET_free (to_match);
  4663. return GNUNET_YES;
  4664. }
  4665. pos = pos->next;
  4666. }
  4667. pos = GNUNET_malloc (sizeof (struct DuplicateStats));
  4668. pos->unique_string = to_match;
  4669. pos->next = *stats_list;
  4670. *stats_list = pos;
  4671. GNUNET_free (unix_domain_socket);
  4672. return GNUNET_NO;
  4673. }
  4674. /**
  4675. * Iterate over all (running) peers in the peer group, retrieve
  4676. * all statistics from each.
  4677. *
  4678. * @param pg the peergroup to iterate statistics of
  4679. * @param cont continuation to call once all stats have been retrieved
  4680. * @param proc processing function for each statistic from each peer
  4681. * @param cls closure to pass to proc
  4682. *
  4683. */
  4684. void
  4685. GNUNET_TESTING_get_statistics(struct GNUNET_TESTING_PeerGroup *pg,
  4686. GNUNET_STATISTICS_Callback cont,
  4687. GNUNET_TESTING_STATISTICS_Iterator proc,
  4688. void *cls)
  4689. {
  4690. struct StatsIterateContext *stats_context;
  4691. struct StatsCoreContext *core_ctx;
  4692. unsigned int i;
  4693. unsigned int total_count;
  4694. struct DuplicateStats *stats_list;
  4695. struct DuplicateStats *pos;
  4696. stats_list = NULL;
  4697. /* Allocate a single stats iteration context */
  4698. stats_context = GNUNET_malloc (sizeof (struct StatsIterateContext));
  4699. stats_context->cont = cont;
  4700. stats_context->proc = proc;
  4701. stats_context->cls = cls;
  4702. stats_context->pg = pg;
  4703. total_count = 0;
  4704. for (i = 0; i < pg->total; i++)
  4705. {
  4706. if ((pg->peers[i].daemon->running == GNUNET_YES) && (GNUNET_NO
  4707. == stats_check_existing (pg, &pg->peers[i], &stats_list)))
  4708. {
  4709. /* Allocate one core context per core we need to connect to */
  4710. core_ctx = GNUNET_malloc (sizeof (struct StatsCoreContext));
  4711. core_ctx->daemon = pg->peers[i].daemon;
  4712. /* Set back pointer to topology iteration context */
  4713. core_ctx->iter_context = stats_context;
  4714. GNUNET_SCHEDULER_add_now (&schedule_get_statistics, core_ctx);
  4715. total_count++;
  4716. }
  4717. }
  4718. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  4719. "Retrieving stats from %u total instances.\n", total_count);
  4720. stats_context->total = total_count;
  4721. if (stats_list != NULL)
  4722. {
  4723. pos = stats_list;
  4724. while (pos != NULL)
  4725. {
  4726. GNUNET_free (pos->unique_string);
  4727. stats_list = pos->next;
  4728. GNUNET_free (pos);
  4729. pos = stats_list->next;
  4730. }
  4731. }
  4732. return;
  4733. }
  4734. /**
  4735. * Stop the connection process temporarily.
  4736. *
  4737. * @param pg the peer group to stop connecting
  4738. */
  4739. void
  4740. GNUNET_TESTING_stop_connections(struct GNUNET_TESTING_PeerGroup *pg)
  4741. {
  4742. pg->stop_connects = GNUNET_YES;
  4743. }
  4744. /**
  4745. * Resume the connection process temporarily.
  4746. *
  4747. * @param pg the peer group to resume connecting
  4748. */
  4749. void
  4750. GNUNET_TESTING_resume_connections(struct GNUNET_TESTING_PeerGroup *pg)
  4751. {
  4752. pg->stop_connects = GNUNET_NO;
  4753. }
  4754. /**
  4755. * There are many ways to connect peers that are supported by this function.
  4756. * To connect peers in the same topology that was created via the
  4757. * GNUNET_TESTING_create_topology, the topology variable must be set to
  4758. * GNUNET_TESTING_TOPOLOGY_NONE. If the topology variable is specified,
  4759. * a new instance of that topology will be generated and attempted to be
  4760. * connected. This could result in some connections being impossible,
  4761. * because some topologies are non-deterministic.
  4762. *
  4763. * @param pg the peer group struct representing the running peers
  4764. * @param topology which topology to connect the peers in
  4765. * @param options options for connecting the topology
  4766. * @param option_modifier modifier for options that take a parameter
  4767. * @param connect_timeout how long to wait before giving up on connecting
  4768. * two peers
  4769. * @param connect_attempts how many times to attempt to connect two peers
  4770. * over the connect_timeout duration
  4771. * @param notify_callback notification to be called once all connections completed
  4772. * @param notify_cls closure for notification callback
  4773. *
  4774. * @return the number of connections that will be attempted, GNUNET_SYSERR on error
  4775. */
  4776. int
  4777. GNUNET_TESTING_connect_topology(
  4778. struct GNUNET_TESTING_PeerGroup *pg,
  4779. enum GNUNET_TESTING_Topology topology,
  4780. enum GNUNET_TESTING_TopologyOption options,
  4781. double option_modifier,
  4782. struct GNUNET_TIME_Relative connect_timeout,
  4783. unsigned int connect_attempts,
  4784. GNUNET_TESTING_NotifyCompletion notify_callback,
  4785. void *notify_cls)
  4786. {
  4787. switch (topology)
  4788. {
  4789. case GNUNET_TESTING_TOPOLOGY_CLIQUE:
  4790. #if VERBOSE_TOPOLOGY
  4791. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  4792. _("Creating clique CONNECT topology\n"));
  4793. #endif
  4794. create_clique (pg, &add_connections, CONNECT, GNUNET_NO);
  4795. break;
  4796. case GNUNET_TESTING_TOPOLOGY_SMALL_WORLD_RING:
  4797. #if VERBOSE_TOPOLOGY
  4798. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  4799. _("Creating small world (ring) CONNECT topology\n"));
  4800. #endif
  4801. create_small_world_ring (pg, &add_connections, CONNECT);
  4802. break;
  4803. case GNUNET_TESTING_TOPOLOGY_SMALL_WORLD:
  4804. #if VERBOSE_TOPOLOGY
  4805. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  4806. _("Creating small world (2d-torus) CONNECT topology\n"));
  4807. #endif
  4808. create_small_world (pg, &add_connections, CONNECT);
  4809. break;
  4810. case GNUNET_TESTING_TOPOLOGY_RING:
  4811. #if VERBOSE_TOPOLOGY
  4812. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _("Creating ring CONNECT topology\n"));
  4813. #endif
  4814. create_ring (pg, &add_connections, CONNECT);
  4815. break;
  4816. case GNUNET_TESTING_TOPOLOGY_2D_TORUS:
  4817. #if VERBOSE_TOPOLOGY
  4818. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  4819. _("Creating 2d torus CONNECT topology\n"));
  4820. #endif
  4821. create_2d_torus (pg, &add_connections, CONNECT);
  4822. break;
  4823. case GNUNET_TESTING_TOPOLOGY_ERDOS_RENYI:
  4824. #if VERBOSE_TOPOLOGY
  4825. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  4826. _("Creating Erdos-Renyi CONNECT topology\n"));
  4827. #endif
  4828. create_erdos_renyi (pg, &add_connections, CONNECT);
  4829. break;
  4830. case GNUNET_TESTING_TOPOLOGY_INTERNAT:
  4831. #if VERBOSE_TOPOLOGY
  4832. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  4833. _("Creating InterNAT CONNECT topology\n"));
  4834. #endif
  4835. create_nated_internet (pg, &add_connections, CONNECT);
  4836. break;
  4837. case GNUNET_TESTING_TOPOLOGY_SCALE_FREE:
  4838. #if VERBOSE_TOPOLOGY
  4839. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  4840. _("Creating Scale Free CONNECT topology\n"));
  4841. #endif
  4842. create_scale_free (pg, &add_connections, CONNECT);
  4843. break;
  4844. case GNUNET_TESTING_TOPOLOGY_LINE:
  4845. #if VERBOSE_TOPOLOGY
  4846. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  4847. _("Creating straight line CONNECT topology\n"));
  4848. #endif
  4849. create_line (pg, &add_connections, CONNECT);
  4850. break;
  4851. case GNUNET_TESTING_TOPOLOGY_NONE:
  4852. #if VERBOSE_TOPOLOGY
  4853. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _("Creating no CONNECT topology\n"));
  4854. #endif
  4855. copy_allowed_topology (pg);
  4856. break;
  4857. default:
  4858. GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _
  4859. ("Unknown topology specification, can't connect peers!\n"));
  4860. return GNUNET_SYSERR;
  4861. }
  4862. switch (options)
  4863. {
  4864. case GNUNET_TESTING_TOPOLOGY_OPTION_RANDOM:
  4865. #if VERBOSE_TOPOLOGY
  4866. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _
  4867. ("Connecting random subset (%'.2f percent) of possible peers\n"), 100
  4868. * option_modifier);
  4869. #endif
  4870. choose_random_connections (pg, option_modifier);
  4871. break;
  4872. case GNUNET_TESTING_TOPOLOGY_OPTION_MINIMUM:
  4873. #if VERBOSE_TOPOLOGY
  4874. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  4875. _("Connecting a minimum of %u peers each (if possible)\n"),
  4876. (unsigned int) option_modifier);
  4877. #endif
  4878. choose_minimum (pg, (unsigned int) option_modifier);
  4879. break;
  4880. case GNUNET_TESTING_TOPOLOGY_OPTION_DFS:
  4881. #if VERBOSE_TOPOLOGY
  4882. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _
  4883. ("Using DFS to connect a minimum of %u peers each (if possible)\n"),
  4884. (unsigned int) option_modifier);
  4885. #endif
  4886. #if FIXME
  4887. perform_dfs (pg, (int) option_modifier);
  4888. #endif
  4889. break;
  4890. case GNUNET_TESTING_TOPOLOGY_OPTION_ADD_CLOSEST:
  4891. #if VERBOSE_TOPOLOGY
  4892. GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _
  4893. ("Finding additional %u closest peers each (if possible)\n"),
  4894. (unsigned int) option_modifier);
  4895. #endif
  4896. #if FIXME
  4897. add_closest (pg, (unsigned int) option_modifier,
  4898. &add_connections, CONNECT);
  4899. #endif
  4900. break;
  4901. case GNUNET_TESTING_TOPOLOGY_OPTION_NONE:
  4902. break;
  4903. case GNUNET_TESTING_TOPOLOGY_OPTION_ALL:
  4904. break;
  4905. default:
  4906. break;
  4907. }
  4908. return connect_topology (pg, connect_timeout, connect_attempts,
  4909. notify_callback, notify_cls);
  4910. }
  4911. /**
  4912. * Lookup and return the number of SSH connections to a host.
  4913. *
  4914. * @param hostname the hostname to lookup in the list
  4915. * @param pg the peergroup that the host belongs to
  4916. *
  4917. * @return the number of current ssh connections to the host
  4918. */
  4919. static unsigned int
  4920. count_outstanding_at_host(const char *hostname,
  4921. struct GNUNET_TESTING_PeerGroup *pg)
  4922. {
  4923. struct OutstandingSSH *pos;
  4924. pos = pg->ssh_head;
  4925. while ((pos != NULL) && (strcmp (pos->hostname, hostname) != 0))
  4926. pos = pos->next;
  4927. GNUNET_assert(pos != NULL);
  4928. return pos->outstanding;
  4929. }
  4930. /**
  4931. * Increment the number of SSH connections to a host by one.
  4932. *
  4933. * @param hostname the hostname to lookup in the list
  4934. * @param pg the peergroup that the host belongs to
  4935. *
  4936. */
  4937. static void
  4938. increment_outstanding_at_host(const char *hostname,
  4939. struct GNUNET_TESTING_PeerGroup *pg)
  4940. {
  4941. struct OutstandingSSH *pos;
  4942. pos = pg->ssh_head;
  4943. while ((pos != NULL) && (strcmp (pos->hostname, hostname) != 0))
  4944. pos = pos->next;
  4945. GNUNET_assert(pos != NULL);
  4946. pos->outstanding++;
  4947. }
  4948. /**
  4949. * Decrement the number of SSH connections to a host by one.
  4950. *
  4951. * @param hostname the hostname to lookup in the list
  4952. * @param pg the peergroup that the host belongs to
  4953. *
  4954. */
  4955. static void
  4956. decrement_outstanding_at_host(const char *hostname,
  4957. struct GNUNET_TESTING_PeerGroup *pg)
  4958. {
  4959. struct OutstandingSSH *pos;
  4960. pos = pg->ssh_head;
  4961. while ((pos != NULL) && (strcmp (pos->hostname, hostname) != 0))
  4962. pos = pos->next;
  4963. GNUNET_assert(pos != NULL);
  4964. pos->outstanding--;
  4965. }
  4966. /**
  4967. * Callback that is called whenever a hostkey is generated
  4968. * for a peer. Call the real callback and decrement the
  4969. * starting counter for the peergroup.
  4970. *
  4971. * @param cls closure
  4972. * @param id identifier for the daemon, NULL on error
  4973. * @param d handle for the daemon
  4974. * @param emsg error message (NULL on success)
  4975. */
  4976. static void
  4977. internal_hostkey_callback(void *cls, const struct GNUNET_PeerIdentity *id,
  4978. struct GNUNET_TESTING_Daemon *d, const char *emsg)
  4979. {
  4980. struct InternalStartContext *internal_context = cls;
  4981. internal_context->peer->pg->starting--;
  4982. internal_context->peer->pg->started++;
  4983. if (internal_context->hostname != NULL)
  4984. decrement_outstanding_at_host (internal_context->hostname,
  4985. internal_context->peer->pg);
  4986. if (internal_context->hostkey_callback != NULL)
  4987. internal_context->hostkey_callback (internal_context->hostkey_cls, id, d,
  4988. emsg);
  4989. else if (internal_context->peer->pg->started
  4990. == internal_context->peer->pg->total)
  4991. {
  4992. internal_context->peer->pg->started = 0; /* Internal startup may use this counter! */
  4993. GNUNET_TESTING_daemons_continue_startup (internal_context->peer->pg);
  4994. }
  4995. }
  4996. /**
  4997. * Callback that is called whenever a peer has finished starting.
  4998. * Call the real callback and decrement the starting counter
  4999. * for the peergroup.
  5000. *
  5001. * @param cls closure
  5002. * @param id identifier for the daemon, NULL on error
  5003. * @param cfg config
  5004. * @param d handle for the daemon
  5005. * @param emsg error message (NULL on success)
  5006. */
  5007. static void
  5008. internal_startup_callback(void *cls, const struct GNUNET_PeerIdentity *id,
  5009. const struct GNUNET_CONFIGURATION_Handle *cfg,
  5010. struct GNUNET_TESTING_Daemon *d, const char *emsg)
  5011. {
  5012. struct InternalStartContext *internal_context = cls;
  5013. internal_context->peer->pg->starting--;
  5014. if (internal_context->hostname != NULL)
  5015. decrement_outstanding_at_host (internal_context->hostname,
  5016. internal_context->peer->pg);
  5017. if (internal_context->start_cb != NULL)
  5018. internal_context->start_cb (internal_context->start_cb_cls, id, cfg, d,
  5019. emsg);
  5020. }
  5021. static void
  5022. internal_continue_startup(void *cls,
  5023. const struct GNUNET_SCHEDULER_TaskContext *tc)
  5024. {
  5025. struct InternalStartContext *internal_context = cls;
  5026. if ( (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
  5027. {
  5028. return;
  5029. }
  5030. if ((internal_context->peer->pg->starting
  5031. < internal_context->peer->pg->max_concurrent_ssh)
  5032. || ((internal_context->hostname != NULL)
  5033. && (count_outstanding_at_host (internal_context->hostname,
  5034. internal_context->peer->pg)
  5035. < internal_context->peer->pg->max_concurrent_ssh)))
  5036. {
  5037. if (internal_context->hostname != NULL)
  5038. increment_outstanding_at_host (internal_context->hostname,
  5039. internal_context->peer->pg);
  5040. internal_context->peer->pg->starting++;
  5041. GNUNET_TESTING_daemon_continue_startup (internal_context->peer->daemon);
  5042. }
  5043. else
  5044. {
  5045. GNUNET_SCHEDULER_add_delayed (
  5046. GNUNET_TIME_relative_multiply (
  5047. GNUNET_TIME_UNIT_MILLISECONDS,
  5048. 100),
  5049. &internal_continue_startup,
  5050. internal_context);
  5051. }
  5052. }
  5053. /**
  5054. * Callback for informing us about a successful
  5055. * or unsuccessful churn start call.
  5056. *
  5057. * @param cls a ChurnContext
  5058. * @param id the peer identity of the started peer
  5059. * @param cfg the handle to the configuration of the peer
  5060. * @param d handle to the daemon for the peer
  5061. * @param emsg NULL on success, non-NULL on failure
  5062. *
  5063. */
  5064. void
  5065. churn_start_callback(void *cls, const struct GNUNET_PeerIdentity *id,
  5066. const struct GNUNET_CONFIGURATION_Handle *cfg,
  5067. struct GNUNET_TESTING_Daemon *d, const char *emsg)
  5068. {
  5069. struct ChurnRestartContext *startup_ctx = cls;
  5070. struct ChurnContext *churn_ctx = startup_ctx->churn_ctx;
  5071. unsigned int total_left;
  5072. char *error_message;
  5073. error_message = NULL;
  5074. if (emsg != NULL)
  5075. {
  5076. GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
  5077. "Churn stop callback failed with error `%s'\n", emsg);
  5078. churn_ctx->num_failed_start++;
  5079. }
  5080. else
  5081. {
  5082. churn_ctx->num_to_start--;
  5083. }
  5084. total_left = (churn_ctx->num_to_stop - churn_ctx->num_failed_stop)
  5085. + (churn_ctx->num_to_start - churn_ctx->num_failed_start);
  5086. if (total_left == 0)
  5087. {
  5088. if ((churn_ctx->num_failed_stop > 0) || (churn_ctx->num_failed_start > 0))
  5089. GNUNET_asprintf (
  5090. &error_message,
  5091. "Churn didn't complete successfully, %u peers failed to start %u peers failed to be stopped!",
  5092. churn_ctx->num_failed_start,
  5093. churn_ctx->num_failed_stop);
  5094. churn_ctx->cb (churn_ctx->cb_cls, error_message);
  5095. GNUNET_free_non_null (error_message);
  5096. GNUNET_free (churn_ctx);
  5097. GNUNET_free (startup_ctx);
  5098. }
  5099. }
  5100. static void
  5101. schedule_churn_restart(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
  5102. {
  5103. struct PeerRestartContext *peer_restart_ctx = cls;
  5104. struct ChurnRestartContext *startup_ctx = peer_restart_ctx->churn_restart_ctx;
  5105. if (startup_ctx->outstanding > startup_ctx->pg->max_concurrent_ssh)
  5106. GNUNET_SCHEDULER_add_delayed (
  5107. GNUNET_TIME_relative_multiply (
  5108. GNUNET_TIME_UNIT_MILLISECONDS,
  5109. 100),
  5110. &schedule_churn_restart, peer_restart_ctx);
  5111. else
  5112. {
  5113. if (startup_ctx->churn_ctx->service != NULL)
  5114. GNUNET_TESTING_daemon_start_stopped_service (peer_restart_ctx->daemon,
  5115. startup_ctx->churn_ctx->service,
  5116. startup_ctx->timeout,
  5117. &churn_start_callback, startup_ctx);
  5118. else
  5119. GNUNET_TESTING_daemon_start_stopped (peer_restart_ctx->daemon,
  5120. startup_ctx->timeout,
  5121. &churn_start_callback, startup_ctx);
  5122. GNUNET_free (peer_restart_ctx);
  5123. }
  5124. }
  5125. /**
  5126. * Callback for informing us about a successful
  5127. * or unsuccessful churn start call.
  5128. *
  5129. * @param cls a struct ServiceStartContext *startup_ctx
  5130. * @param id the peer identity of the started peer
  5131. * @param cfg the handle to the configuration of the peer
  5132. * @param d handle to the daemon for the peer
  5133. * @param emsg NULL on success, non-NULL on failure
  5134. *
  5135. */
  5136. void
  5137. service_start_callback(void *cls,
  5138. const struct GNUNET_PeerIdentity *id,
  5139. const struct GNUNET_CONFIGURATION_Handle *cfg,
  5140. struct GNUNET_TESTING_Daemon *d,
  5141. const char *emsg)
  5142. {
  5143. struct ServiceStartContext *startup_ctx = (struct ServiceStartContext *)cls;
  5144. if (emsg != NULL)
  5145. {
  5146. GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
  5147. "Service start failed with error `%s'\n", emsg);
  5148. }
  5149. startup_ctx->outstanding--;
  5150. startup_ctx->remaining--;
  5151. if (startup_ctx->remaining == 0)
  5152. {
  5153. startup_ctx->cb (startup_ctx->cb_cls, NULL);
  5154. GNUNET_free (startup_ctx->service);
  5155. GNUNET_free (startup_ctx);
  5156. }
  5157. }
  5158. static void
  5159. schedule_service_start(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
  5160. {
  5161. struct PeerServiceStartContext *peer_ctx = cls;
  5162. struct ServiceStartContext *startup_ctx = peer_ctx->start_ctx;
  5163. if (startup_ctx->outstanding > startup_ctx->pg->max_concurrent_ssh)
  5164. GNUNET_SCHEDULER_add_delayed (
  5165. GNUNET_TIME_relative_multiply (
  5166. GNUNET_TIME_UNIT_MILLISECONDS,
  5167. 100),
  5168. &schedule_service_start, peer_ctx);
  5169. else
  5170. {
  5171. GNUNET_TESTING_daemon_start_service (peer_ctx->daemon,
  5172. startup_ctx->service,
  5173. startup_ctx->timeout,
  5174. &service_start_callback, startup_ctx);
  5175. GNUNET_free (peer_ctx);
  5176. }
  5177. }
  5178. static void
  5179. internal_start(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
  5180. {
  5181. struct InternalStartContext *internal_context = cls;
  5182. if ( (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
  5183. {
  5184. return;
  5185. }
  5186. if ((internal_context->peer->pg->starting
  5187. < internal_context->peer->pg->max_concurrent_ssh)
  5188. || ((internal_context->hostname != NULL)
  5189. && (count_outstanding_at_host (internal_context->hostname,
  5190. internal_context->peer->pg)
  5191. < internal_context->peer->pg->max_concurrent_ssh)))
  5192. {
  5193. if (internal_context->hostname != NULL)
  5194. increment_outstanding_at_host (internal_context->hostname,
  5195. internal_context->peer->pg);
  5196. internal_context->peer->pg->starting++;
  5197. internal_context->peer->daemon
  5198. = GNUNET_TESTING_daemon_start (internal_context->peer->cfg,
  5199. internal_context->timeout,
  5200. GNUNET_NO,
  5201. internal_context->hostname,
  5202. internal_context->username,
  5203. internal_context->sshport,
  5204. internal_context->hostkey,
  5205. &internal_hostkey_callback,
  5206. internal_context,
  5207. &internal_startup_callback,
  5208. internal_context);
  5209. }
  5210. else
  5211. {
  5212. GNUNET_SCHEDULER_add_delayed (
  5213. GNUNET_TIME_relative_multiply (
  5214. GNUNET_TIME_UNIT_MILLISECONDS,
  5215. 100),
  5216. &internal_start, internal_context);
  5217. }
  5218. }
  5219. #if USE_START_HELPER
  5220. struct PeerStartHelperContext
  5221. {
  5222. struct GNUNET_TESTING_PeerGroup *pg;
  5223. struct HostData *host;
  5224. struct GNUNET_OS_Process *proc;
  5225. };
  5226. static void
  5227. check_peers_started (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
  5228. {
  5229. struct PeerStartHelperContext *helper = cls;
  5230. enum GNUNET_OS_ProcessStatusType type;
  5231. unsigned long code;
  5232. unsigned int i;
  5233. GNUNET_TESTING_NotifyDaemonRunning cb;
  5234. if (GNUNET_NO == GNUNET_OS_process_status (helper->proc, &type, &code)) /* Still running, wait some more! */
  5235. {
  5236. GNUNET_SCHEDULER_add_delayed(GNUNET_CONSTANTS_EXEC_WAIT, &check_peers_started, helper);
  5237. return;
  5238. }
  5239. helper->pg->starting--;
  5240. if (helper->pg->starting == 0) /* All peers have finished starting! */
  5241. {
  5242. /* Call the peer started callback for each peer, set proper FSM state (?) */
  5243. for (i = 0; i < helper->pg->total; i++)
  5244. {
  5245. cb = helper->pg->peers[i].daemon->cb;
  5246. helper->pg->peers[i].daemon->cb = NULL;
  5247. helper->pg->peers[i].daemon->running = GNUNET_YES;
  5248. helper->pg->peers[i].daemon->phase = SP_START_DONE;
  5249. if (NULL != cb)
  5250. {
  5251. if ((type != GNUNET_OS_PROCESS_EXITED) || (code != 0))
  5252. cb (helper->pg->peers[i].daemon->cb_cls,
  5253. &helper->pg->peers[i].daemon->id,
  5254. helper->pg->peers[i].daemon->cfg, helper->pg->peers[i].daemon,
  5255. "Failed to execute peerStartHelper.pl, or return code bad!");
  5256. else
  5257. cb (helper->pg->peers[i].daemon->cb_cls,
  5258. &helper->pg->peers[i].daemon->id,
  5259. helper->pg->peers[i].daemon->cfg, helper->pg->peers[i].daemon,
  5260. NULL);
  5261. }
  5262. }
  5263. }
  5264. GNUNET_OS_process_close(helper->proc);
  5265. }
  5266. static void
  5267. start_peer_helper (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
  5268. {
  5269. struct PeerStartHelperContext *helper = cls;
  5270. char *baseservicehome;
  5271. char *tempdir;
  5272. char *arg;
  5273. /* ssh user@host peerStartHelper /path/to/basedirectory */
  5274. GNUNET_assert(GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (helper->pg->cfg, "PATHS", "SERVICEHOME",
  5275. &baseservicehome));
  5276. GNUNET_asprintf(&tempdir, "%s/%s/", baseservicehome, helper->host->hostname);
  5277. if (NULL != helper->host->username)
  5278. GNUNET_asprintf (&arg, "%s@%s", helper->host->username, helper->host->hostname);
  5279. else
  5280. GNUNET_asprintf (&arg, "%s", helper->host->hostname);
  5281. /* FIXME: Doesn't support ssh_port option! */
  5282. helper->proc = GNUNET_OS_start_process (NULL, NULL, "ssh", "ssh", arg,
  5283. "peerStartHelper.pl", tempdir, NULL);
  5284. GNUNET_assert(helper->proc != NULL);
  5285. GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "starting peers with cmd ssh %s %s %s\n", arg, "peerStartHelper.pl", tempdir);
  5286. GNUNET_SCHEDULER_add_now (&check_peers_started, helper);
  5287. GNUNET_free (tempdir);
  5288. GNUNET_free (baseservicehome);
  5289. GNUNET_free (arg);
  5290. }
  5291. #endif
  5292. /**
  5293. * Function which continues a peer group starting up
  5294. * after successfully generating hostkeys for each peer.
  5295. *
  5296. * @param pg the peer group to continue starting
  5297. *
  5298. */
  5299. void
  5300. GNUNET_TESTING_daemons_continue_startup(struct GNUNET_TESTING_PeerGroup *pg)
  5301. {
  5302. unsigned int i;
  5303. #if USE_START_HELPER
  5304. if ((pg->num_hosts > 0) && (pg->hostkey_data != NULL))
  5305. {
  5306. struct PeerStartHelperContext *helper;
  5307. pg->starting = pg->num_hosts;
  5308. for (i = 0; i < pg->num_hosts; i++)
  5309. {
  5310. helper = GNUNET_malloc(sizeof(struct PeerStartHelperContext));
  5311. helper->pg = pg;
  5312. helper->host = &pg->hosts[i];
  5313. GNUNET_SCHEDULER_add_now(&start_peer_helper, helper);
  5314. }
  5315. }
  5316. else
  5317. {
  5318. pg->starting = 0;
  5319. for (i = 0; i < pg->total; i++)
  5320. {
  5321. GNUNET_SCHEDULER_add_now (&internal_continue_startup,
  5322. &pg->peers[i].internal_context);
  5323. }
  5324. }
  5325. #else
  5326. pg->starting = 0;
  5327. for (i = 0; i < pg->total; i++)
  5328. {
  5329. GNUNET_SCHEDULER_add_now (&internal_continue_startup,
  5330. &pg->peers[i].internal_context);
  5331. }
  5332. #endif
  5333. }
  5334. #if USE_START_HELPER
  5335. static void
  5336. call_hostkey_callbacks (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
  5337. {
  5338. struct GNUNET_TESTING_PeerGroup *pg = cls;
  5339. unsigned int i;
  5340. for (i = 0; i < pg->total; i++)
  5341. {
  5342. if (pg->peers[i].internal_context.hostkey_callback != NULL)
  5343. pg->peers[i].internal_context.hostkey_callback (pg->peers[i].internal_context.hostkey_cls,
  5344. &pg->peers[i].daemon->id,
  5345. pg->peers[i].daemon,
  5346. NULL);
  5347. }
  5348. if (pg->peers[0].internal_context.hostkey_callback == NULL)
  5349. GNUNET_TESTING_daemons_continue_startup (pg);
  5350. }
  5351. #endif
  5352. /**
  5353. * Start count gnunet instances with the same set of transports and
  5354. * applications. The port numbers (any option called "PORT") will be
  5355. * adjusted to ensure that no two peers running on the same system
  5356. * have the same port(s) in their respective configurations.
  5357. *
  5358. * @param cfg configuration template to use
  5359. * @param total number of daemons to start
  5360. * @param max_concurrent_connections for testing, how many peers can
  5361. * we connect to simultaneously
  5362. * @param max_concurrent_ssh when starting with ssh, how many ssh
  5363. * connections will we allow at once (based on remote hosts allowed!)
  5364. * @param timeout total time allowed for peers to start
  5365. * @param hostkey_callback function to call on each peers hostkey generation
  5366. * if NULL, peers will be started by this call, if non-null,
  5367. * GNUNET_TESTING_daemons_continue_startup must be called after
  5368. * successful hostkey generation
  5369. * @param hostkey_cls closure for hostkey callback
  5370. * @param cb function to call on each daemon that was started
  5371. * @param cb_cls closure for cb
  5372. * @param connect_callback function to call each time two hosts are connected
  5373. * @param connect_callback_cls closure for connect_callback
  5374. * @param hostnames linked list of host structs to use to start peers on
  5375. * (NULL to run on localhost only)
  5376. *
  5377. * @return NULL on error, otherwise handle to control peer group
  5378. */
  5379. struct GNUNET_TESTING_PeerGroup *
  5380. GNUNET_TESTING_daemons_start(const struct GNUNET_CONFIGURATION_Handle *cfg,
  5381. unsigned int total,
  5382. unsigned int max_concurrent_connections,
  5383. unsigned int max_concurrent_ssh,
  5384. struct GNUNET_TIME_Relative timeout,
  5385. GNUNET_TESTING_NotifyHostkeyCreated hostkey_callback,
  5386. void *hostkey_cls,
  5387. GNUNET_TESTING_NotifyDaemonRunning cb,
  5388. void *cb_cls,
  5389. GNUNET_TESTING_NotifyConnection connect_callback,
  5390. void *connect_callback_cls,
  5391. const struct GNUNET_TESTING_Host *hostnames)
  5392. {
  5393. struct GNUNET_TESTING_PeerGroup *pg;
  5394. const struct GNUNET_TESTING_Host *hostpos;
  5395. const char *hostname;
  5396. const char *username;
  5397. char *baseservicehome;
  5398. char *newservicehome;
  5399. char *tmpdir;
  5400. char *hostkeys_file;
  5401. char *arg;
  5402. char *ssh_port_str;
  5403. struct GNUNET_DISK_FileHandle *fd;
  5404. struct GNUNET_CONFIGURATION_Handle *pcfg;
  5405. unsigned int off;
  5406. struct OutstandingSSH *ssh_entry;
  5407. unsigned int hostcnt;
  5408. unsigned int i;
  5409. uint16_t minport;
  5410. uint16_t sshport;
  5411. uint32_t upnum;
  5412. uint32_t fdnum;
  5413. uint64_t fs;
  5414. uint64_t total_hostkeys;
  5415. struct GNUNET_OS_Process *proc;
  5416. username = NULL;
  5417. if (0 == total)
  5418. {
  5419. GNUNET_break (0);
  5420. return NULL;
  5421. }
  5422. upnum = 0;
  5423. fdnum = 0;
  5424. pg = GNUNET_malloc (sizeof (struct GNUNET_TESTING_PeerGroup));
  5425. pg->cfg = cfg;
  5426. pg->notify_connection = connect_callback;
  5427. pg->notify_connection_cls = connect_callback_cls;
  5428. pg->total = total;
  5429. pg->max_timeout = GNUNET_TIME_relative_to_absolute (timeout);
  5430. pg->peers = GNUNET_malloc (total * sizeof (struct PeerData));
  5431. pg->max_outstanding_connections = max_concurrent_connections;
  5432. pg->max_concurrent_ssh = max_concurrent_ssh;
  5433. if (NULL != hostnames)
  5434. {
  5435. off = 0;
  5436. hostpos = hostnames;
  5437. while (hostpos != NULL)
  5438. {
  5439. hostpos = hostpos->next;
  5440. off++;
  5441. }
  5442. pg->hosts = GNUNET_malloc (off * sizeof (struct HostData));
  5443. off = 0;
  5444. hostpos = hostnames;
  5445. while (hostpos != NULL)
  5446. {
  5447. pg->hosts[off].minport = LOW_PORT;
  5448. pg->hosts[off].hostname = GNUNET_strdup (hostpos->hostname);
  5449. if (hostpos->username != NULL)
  5450. pg->hosts[off].username = GNUNET_strdup (hostpos->username);
  5451. pg->hosts[off].sshport = hostpos->port;
  5452. hostpos = hostpos->next;
  5453. off++;
  5454. }
  5455. if (off == 0)
  5456. {
  5457. pg->hosts = NULL;
  5458. }
  5459. hostcnt = off;
  5460. minport = 0;
  5461. pg->num_hosts = off;
  5462. }
  5463. else
  5464. {
  5465. hostcnt = 0;
  5466. minport = LOW_PORT;
  5467. }
  5468. /* Create the servicehome directory for each remote peer */
  5469. GNUNET_assert(GNUNET_OK ==
  5470. GNUNET_CONFIGURATION_get_value_string (cfg, "PATHS", "SERVICEHOME",
  5471. &baseservicehome));
  5472. for (i = 0; i < pg->num_hosts; i++)
  5473. {
  5474. ssh_entry = GNUNET_malloc(sizeof(struct OutstandingSSH));
  5475. ssh_entry->hostname = pg->hosts[i].hostname; /* Don't free! */
  5476. GNUNET_CONTAINER_DLL_insert(pg->ssh_head, pg->ssh_tail, ssh_entry);
  5477. GNUNET_asprintf(&tmpdir, "%s/%s", baseservicehome, pg->hosts[i].hostname);
  5478. if (NULL != pg->hosts[i].username)
  5479. GNUNET_asprintf (&arg, "%s@%s", pg->hosts[i].username,
  5480. pg->hosts[i].hostname);
  5481. else
  5482. GNUNET_asprintf (&arg, "%s", pg->hosts[i].hostname);
  5483. if (pg->hosts[i].sshport != 0)
  5484. {
  5485. GNUNET_asprintf (&ssh_port_str, "%d", pg->hosts[i].sshport);
  5486. proc = GNUNET_OS_start_process (NULL, NULL, "ssh", "ssh", "-P",
  5487. ssh_port_str,
  5488. #if !DEBUG_TESTING
  5489. "-q",
  5490. #endif
  5491. arg, "mkdir -p", tmpdir,
  5492. NULL);
  5493. }
  5494. else
  5495. proc = GNUNET_OS_start_process (NULL, NULL, "ssh", "ssh", arg,
  5496. "mkdir -p", tmpdir, NULL);
  5497. GNUNET_assert(proc != NULL);
  5498. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  5499. "Creating remote dir with command ssh %s %s %s\n", arg,
  5500. " mkdir -p ", tmpdir);
  5501. GNUNET_free(tmpdir);
  5502. GNUNET_free(arg);
  5503. GNUNET_OS_process_wait (proc);
  5504. GNUNET_OS_process_close(proc);
  5505. }
  5506. GNUNET_free(baseservicehome);
  5507. baseservicehome = NULL;
  5508. if (GNUNET_YES == GNUNET_CONFIGURATION_get_value_string (cfg, "TESTING",
  5509. "HOSTKEYSFILE",
  5510. &hostkeys_file))
  5511. {
  5512. if (GNUNET_YES != GNUNET_DISK_file_test (hostkeys_file))
  5513. GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
  5514. _("Could not read hostkeys file!\n"));
  5515. else
  5516. {
  5517. /* Check hostkey file size, read entire thing into memory */
  5518. fd = GNUNET_DISK_file_open (hostkeys_file,
  5519. GNUNET_DISK_OPEN_READ,
  5520. GNUNET_DISK_PERM_NONE);
  5521. if (NULL == fd)
  5522. {
  5523. GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
  5524. "open",
  5525. hostkeys_file);
  5526. GNUNET_free (hostkeys_file);
  5527. for (i=0;i<pg->num_hosts;i++)
  5528. {
  5529. GNUNET_free (pg->hosts[i].hostname);
  5530. GNUNET_free_non_null (pg->hosts[i].username);
  5531. }
  5532. GNUNET_free (pg->peers);
  5533. GNUNET_free (pg->hosts);
  5534. GNUNET_free (pg);
  5535. return NULL;
  5536. }
  5537. if (GNUNET_YES != GNUNET_DISK_file_size (hostkeys_file, &fs,
  5538. GNUNET_YES))
  5539. fs = 0;
  5540. GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
  5541. "Found file size %llu for hostkeys, expect hostkeys to be size %d\n",
  5542. fs, HOSTKEYFILESIZE);
  5543. if (0 != (fs % HOSTKEYFILESIZE))
  5544. {
  5545. GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
  5546. "File size %llu seems incorrect for hostkeys...\n",
  5547. fs);
  5548. }
  5549. else
  5550. {
  5551. total_hostkeys = fs / HOSTKEYFILESIZE;
  5552. GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
  5553. "Will read %llu hostkeys from file\n",
  5554. total_hostkeys);
  5555. pg->hostkey_data = GNUNET_malloc_large (fs);
  5556. GNUNET_assert (fs == GNUNET_DISK_file_read (fd, pg->hostkey_data, fs));
  5557. }
  5558. GNUNET_assert(GNUNET_OK == GNUNET_DISK_file_close(fd));
  5559. }
  5560. GNUNET_free(hostkeys_file);
  5561. }
  5562. for (off = 0; off < total; off++)
  5563. {
  5564. if (hostcnt > 0)
  5565. {
  5566. hostname = pg->hosts[off % hostcnt].hostname;
  5567. username = pg->hosts[off % hostcnt].username;
  5568. sshport = pg->hosts[off % hostcnt].sshport;
  5569. pcfg = make_config (cfg, off, &pg->hosts[off % hostcnt].minport,
  5570. &upnum, hostname, &fdnum);
  5571. }
  5572. else
  5573. {
  5574. hostname = NULL;
  5575. username = NULL;
  5576. sshport = 0;
  5577. pcfg = make_config (cfg, off, &minport, &upnum, hostname, &fdnum);
  5578. }
  5579. if (NULL == pcfg)
  5580. {
  5581. GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
  5582. _("Could not create configuration for peer number %u on `%s'!\n"),
  5583. off,
  5584. hostname == NULL ? "localhost" : hostname);
  5585. continue;
  5586. }
  5587. if (GNUNET_YES
  5588. == GNUNET_CONFIGURATION_get_value_string (pcfg, "PATHS",
  5589. "SERVICEHOME",
  5590. &baseservicehome))
  5591. {
  5592. if (hostname != NULL)
  5593. GNUNET_asprintf (&newservicehome, "%s/%s/%d/", baseservicehome, hostname, off);
  5594. else
  5595. GNUNET_asprintf (&newservicehome, "%s/%d/", baseservicehome, off);
  5596. GNUNET_free (baseservicehome);
  5597. baseservicehome = NULL;
  5598. }
  5599. else
  5600. {
  5601. tmpdir = getenv ("TMPDIR");
  5602. tmpdir = tmpdir ? tmpdir : "/tmp";
  5603. if (hostname != NULL)
  5604. GNUNET_asprintf (&newservicehome, "%s/%s/%s/%d/", tmpdir, hostname,
  5605. "gnunet-testing-test-test", off);
  5606. else
  5607. GNUNET_asprintf (&newservicehome, "%s/%s/%d/", tmpdir,
  5608. "gnunet-testing-test-test", off);
  5609. }
  5610. GNUNET_CONFIGURATION_set_value_string (pcfg, "PATHS", "SERVICEHOME",
  5611. newservicehome);
  5612. GNUNET_free (newservicehome);
  5613. pg->peers[off].cfg = pcfg;
  5614. pg->peers[off].pg = pg;
  5615. pg->peers[off].internal_context.peer = &pg->peers[off];
  5616. pg->peers[off].internal_context.timeout = timeout;
  5617. pg->peers[off].internal_context.hostname = hostname;
  5618. pg->peers[off].internal_context.username = username;
  5619. pg->peers[off].internal_context.sshport = sshport;
  5620. if (pg->hostkey_data != NULL)
  5621. pg->peers[off].internal_context.hostkey = &pg->hostkey_data[off
  5622. * HOSTKEYFILESIZE];
  5623. pg->peers[off].internal_context.hostkey_callback = hostkey_callback;
  5624. pg->peers[off].internal_context.hostkey_cls = hostkey_cls;
  5625. pg->peers[off].internal_context.start_cb = cb;
  5626. pg->peers[off].internal_context.start_cb_cls = cb_cls;
  5627. #if !USE_START_HELPER
  5628. GNUNET_SCHEDULER_add_now (&internal_start,
  5629. &pg->peers[off].internal_context);
  5630. #else
  5631. if ((pg->hostkey_data != NULL) && (hostcnt > 0))
  5632. {
  5633. pg->peers[off].daemon
  5634. = GNUNET_TESTING_daemon_start (pcfg,
  5635. timeout,
  5636. GNUNET_YES,
  5637. hostname,
  5638. username,
  5639. sshport,
  5640. pg->peers[off].internal_context.hostkey,
  5641. &internal_hostkey_callback,
  5642. &pg->peers[off].internal_context,
  5643. &internal_startup_callback,
  5644. &pg->peers[off].internal_context);
  5645. /**
  5646. * At this point, given that we had a hostkeyfile,
  5647. * we can call the hostkey callback!
  5648. * But first, we should copy (rsync) all of the configs
  5649. * and hostkeys to the remote peers. Then let topology
  5650. * creation happen, then call the peer start helper processes,
  5651. * then set pg->whatever_phase for each peer and let them
  5652. * enter the fsm to get the HELLO's for peers and start connecting.
  5653. */
  5654. }
  5655. else
  5656. {
  5657. GNUNET_SCHEDULER_add_now (&internal_start,
  5658. &pg->peers[off].internal_context);
  5659. }
  5660. #endif
  5661. }
  5662. #if USE_START_HELPER /* Now the peergroup has been set up, hostkeys and configs written to files. */
  5663. if ((pg->hostkey_data != NULL) && (hostcnt > 0))
  5664. {
  5665. for (off = 0; off < hostcnt; off++)
  5666. {
  5667. if (hostcnt > 0)
  5668. {
  5669. hostname = pg->hosts[off % hostcnt].hostname;
  5670. username = pg->hosts[off % hostcnt].username;
  5671. sshport = pg->hosts[off % hostcnt].sshport;
  5672. }
  5673. else
  5674. {
  5675. hostname = NULL;
  5676. username = NULL;
  5677. sshport = 0;
  5678. }
  5679. if (GNUNET_YES
  5680. == GNUNET_CONFIGURATION_get_value_string (cfg, "PATHS",
  5681. "SERVICEHOME",
  5682. &baseservicehome))
  5683. {
  5684. GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "baseservice home is %s\n", baseservicehome);
  5685. if (hostname != NULL)
  5686. GNUNET_asprintf (&newservicehome, "%s/%s/", baseservicehome, hostname);
  5687. else
  5688. GNUNET_asprintf (&newservicehome, "%s/", baseservicehome);
  5689. GNUNET_free (baseservicehome);
  5690. baseservicehome = NULL;
  5691. }
  5692. else
  5693. {
  5694. tmpdir = getenv ("TMPDIR");
  5695. tmpdir = tmpdir ? tmpdir : "/tmp";
  5696. if (hostname != NULL)
  5697. GNUNET_asprintf (&newservicehome, "%s/%s/%s/", tmpdir, hostname,
  5698. "gnunet-testing-test-test");
  5699. else
  5700. GNUNET_asprintf (&newservicehome, "%s/%s/", tmpdir,
  5701. "gnunet-testing-test-test", off);
  5702. }
  5703. if (NULL != username)
  5704. GNUNET_asprintf (&arg,
  5705. "%s@%s:%s",
  5706. username,
  5707. pg->hosts[off].hostname,
  5708. newservicehome);
  5709. else
  5710. GNUNET_asprintf (&arg,
  5711. "%s:%s",
  5712. pg->hosts[off].hostname,
  5713. newservicehome);
  5714. /* FIXME: Doesn't support ssh_port option! */
  5715. proc = GNUNET_OS_start_process (NULL, NULL,
  5716. "rsync",
  5717. "rsync", "-r", newservicehome, arg, NULL);
  5718. GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
  5719. "copying directory with command rsync -r %s %s\n",
  5720. newservicehome, arg);
  5721. GNUNET_free(newservicehome);
  5722. GNUNET_free (arg);
  5723. if (NULL == proc)
  5724. {
  5725. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  5726. _("Could not start `%s' process to copy configuration directory.\n"),
  5727. "scp");
  5728. GNUNET_assert(0);
  5729. }
  5730. GNUNET_OS_process_wait (proc);
  5731. GNUNET_OS_process_close (proc);
  5732. }
  5733. /* Now all the configuration files and hostkeys are copied to the remote host. Call the hostkey callback for each peer! */
  5734. GNUNET_SCHEDULER_add_now (&call_hostkey_callbacks, pg);
  5735. }
  5736. #endif
  5737. return pg;
  5738. }
  5739. /*
  5740. * Get a daemon by number, so callers don't have to do nasty
  5741. * offsetting operation.
  5742. */
  5743. struct GNUNET_TESTING_Daemon *
  5744. GNUNET_TESTING_daemon_get(struct GNUNET_TESTING_PeerGroup *pg,
  5745. unsigned int position)
  5746. {
  5747. if (position < pg->total)
  5748. return pg->peers[position].daemon;
  5749. return NULL;
  5750. }
  5751. /*
  5752. * Get a daemon by peer identity, so callers can
  5753. * retrieve the daemon without knowing it's offset.
  5754. *
  5755. * @param pg the peer group to retrieve the daemon from
  5756. * @param peer_id the peer identity of the daemon to retrieve
  5757. *
  5758. * @return the daemon on success, or NULL if no such peer identity is found
  5759. */
  5760. struct GNUNET_TESTING_Daemon *
  5761. GNUNET_TESTING_daemon_get_by_id(struct GNUNET_TESTING_PeerGroup *pg,
  5762. struct GNUNET_PeerIdentity *peer_id)
  5763. {
  5764. unsigned int i;
  5765. for (i = 0; i < pg->total; i++)
  5766. {
  5767. if (0 == memcmp (&pg->peers[i].daemon->id, peer_id,
  5768. sizeof(struct GNUNET_PeerIdentity)))
  5769. return pg->peers[i].daemon;
  5770. }
  5771. return NULL;
  5772. }
  5773. /**
  5774. * Prototype of a function that will be called when a
  5775. * particular operation was completed the testing library.
  5776. *
  5777. * @param cls closure (a struct RestartContext)
  5778. * @param id id of the peer that was restarted
  5779. * @param cfg handle to the configuration of the peer
  5780. * @param d handle to the daemon that was restarted
  5781. * @param emsg NULL on success
  5782. */
  5783. static void
  5784. restart_callback(void *cls, const struct GNUNET_PeerIdentity *id,
  5785. const struct GNUNET_CONFIGURATION_Handle *cfg,
  5786. struct GNUNET_TESTING_Daemon *d, const char *emsg)
  5787. {
  5788. struct RestartContext *restart_context = cls;
  5789. if (emsg == NULL)
  5790. {
  5791. restart_context->peers_restarted++;
  5792. }
  5793. else
  5794. {
  5795. restart_context->peers_restart_failed++;
  5796. }
  5797. if (restart_context->peers_restarted == restart_context->peer_group->total)
  5798. {
  5799. restart_context->callback (restart_context->callback_cls, NULL);
  5800. GNUNET_free (restart_context);
  5801. }
  5802. else if (restart_context->peers_restart_failed
  5803. + restart_context->peers_restarted == restart_context->peer_group->total)
  5804. {
  5805. restart_context->callback (restart_context->callback_cls,
  5806. "Failed to restart peers!");
  5807. GNUNET_free (restart_context);
  5808. }
  5809. }
  5810. /**
  5811. * Callback for informing us about a successful
  5812. * or unsuccessful churn stop call.
  5813. *
  5814. * @param cls a ChurnContext
  5815. * @param emsg NULL on success, non-NULL on failure
  5816. *
  5817. */
  5818. static void
  5819. churn_stop_callback(void *cls, const char *emsg)
  5820. {
  5821. struct ShutdownContext *shutdown_ctx = cls;
  5822. struct ChurnContext *churn_ctx = shutdown_ctx->cb_cls;
  5823. unsigned int total_left;
  5824. char *error_message;
  5825. error_message = NULL;
  5826. shutdown_ctx->outstanding--;
  5827. if (emsg != NULL)
  5828. {
  5829. GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
  5830. "Churn stop callback failed with error `%s'\n", emsg);
  5831. churn_ctx->num_failed_stop++;
  5832. }
  5833. else
  5834. {
  5835. churn_ctx->num_to_stop--;
  5836. }
  5837. total_left = (churn_ctx->num_to_stop - churn_ctx->num_failed_stop)
  5838. + (churn_ctx->num_to_start - churn_ctx->num_failed_start);
  5839. if (total_left == 0)
  5840. {
  5841. if ((churn_ctx->num_failed_stop > 0) || (churn_ctx->num_failed_start > 0))
  5842. {
  5843. GNUNET_asprintf (
  5844. &error_message,
  5845. "Churn didn't complete successfully, %u peers failed to start %u peers failed to be stopped!",
  5846. churn_ctx->num_failed_start,
  5847. churn_ctx->num_failed_stop);
  5848. }
  5849. churn_ctx->cb (churn_ctx->cb_cls, error_message);
  5850. GNUNET_free_non_null (error_message);
  5851. GNUNET_free (churn_ctx);
  5852. GNUNET_free (shutdown_ctx);
  5853. }
  5854. }
  5855. /**
  5856. * Count the number of running peers.
  5857. *
  5858. * @param pg handle for the peer group
  5859. *
  5860. * @return the number of currently running peers in the peer group
  5861. */
  5862. unsigned int
  5863. GNUNET_TESTING_daemons_running(struct GNUNET_TESTING_PeerGroup *pg)
  5864. {
  5865. unsigned int i;
  5866. unsigned int running = 0;
  5867. for (i = 0; i < pg->total; i++)
  5868. {
  5869. if (pg->peers[i].daemon->running == GNUNET_YES)
  5870. {
  5871. GNUNET_assert (running != -1);
  5872. running++;
  5873. }
  5874. }
  5875. return running;
  5876. }
  5877. /**
  5878. * Task to rate limit the number of outstanding peer shutdown
  5879. * requests. This is necessary for making sure we don't do
  5880. * too many ssh connections at once, but is generally nicer
  5881. * to any system as well (graduated task starts, as opposed
  5882. * to calling gnunet-arm N times all at once).
  5883. */
  5884. static void
  5885. schedule_churn_shutdown_task(void *cls,
  5886. const struct GNUNET_SCHEDULER_TaskContext *tc)
  5887. {
  5888. struct PeerShutdownContext *peer_shutdown_ctx = cls;
  5889. struct ShutdownContext *shutdown_ctx;
  5890. struct ChurnContext *churn_ctx;
  5891. GNUNET_assert (peer_shutdown_ctx != NULL);
  5892. shutdown_ctx = peer_shutdown_ctx->shutdown_ctx;
  5893. GNUNET_assert (shutdown_ctx != NULL);
  5894. churn_ctx = (struct ChurnContext *) shutdown_ctx->cb_cls;
  5895. if (shutdown_ctx->outstanding > churn_ctx->pg->max_concurrent_ssh)
  5896. GNUNET_SCHEDULER_add_delayed (
  5897. GNUNET_TIME_relative_multiply (
  5898. GNUNET_TIME_UNIT_MILLISECONDS,
  5899. 100),
  5900. &schedule_churn_shutdown_task,
  5901. peer_shutdown_ctx);
  5902. else
  5903. {
  5904. shutdown_ctx->outstanding++;
  5905. if (churn_ctx->service != NULL)
  5906. GNUNET_TESTING_daemon_stop_service (peer_shutdown_ctx->daemon,
  5907. churn_ctx->service,
  5908. shutdown_ctx->timeout, shutdown_ctx->cb,
  5909. shutdown_ctx);
  5910. else
  5911. GNUNET_TESTING_daemon_stop (peer_shutdown_ctx->daemon,
  5912. shutdown_ctx->timeout, shutdown_ctx->cb,
  5913. shutdown_ctx, GNUNET_NO, GNUNET_YES);
  5914. GNUNET_free (peer_shutdown_ctx);
  5915. }
  5916. }
  5917. /**
  5918. * Simulate churn by stopping some peers (and possibly
  5919. * re-starting others if churn is called multiple times). This
  5920. * function can only be used to create leave-join churn (peers "never"
  5921. * leave for good). First "voff" random peers that are currently
  5922. * online will be taken offline; then "von" random peers that are then
  5923. * offline will be put back online. No notifications will be
  5924. * generated for any of these operations except for the callback upon
  5925. * completion.
  5926. *
  5927. * @param pg handle for the peer group
  5928. * @param service the service to churn off/on, NULL to churn peer
  5929. * @param voff number of peers that should go offline
  5930. * @param von number of peers that should come back online;
  5931. * must be zero on first call (since "testbed_start"
  5932. * always starts all of the peers)
  5933. * @param timeout how long to wait for operations to finish before
  5934. * giving up
  5935. * @param cb function to call at the end
  5936. * @param cb_cls closure for cb
  5937. */
  5938. void
  5939. GNUNET_TESTING_daemons_churn(struct GNUNET_TESTING_PeerGroup *pg,
  5940. char *service,
  5941. unsigned int voff, unsigned int von,
  5942. struct GNUNET_TIME_Relative timeout,
  5943. GNUNET_TESTING_NotifyCompletion cb, void *cb_cls)
  5944. {
  5945. struct ChurnContext *churn_ctx;
  5946. struct ShutdownContext *shutdown_ctx;
  5947. struct PeerShutdownContext *peer_shutdown_ctx;
  5948. struct PeerRestartContext *peer_restart_ctx;
  5949. struct ChurnRestartContext *churn_startup_ctx;
  5950. unsigned int running;
  5951. unsigned int stopped;
  5952. unsigned int total_running;
  5953. unsigned int total_stopped;
  5954. unsigned int i;
  5955. unsigned int *running_arr;
  5956. unsigned int *stopped_arr;
  5957. unsigned int *running_permute;
  5958. unsigned int *stopped_permute;
  5959. char *pos;
  5960. shutdown_ctx = NULL;
  5961. peer_shutdown_ctx = NULL;
  5962. peer_restart_ctx = NULL;
  5963. churn_startup_ctx = NULL;
  5964. running = 0;
  5965. stopped = 0;
  5966. if ((von == 0) && (voff == 0)) /* No peers at all? */
  5967. {
  5968. cb (cb_cls, NULL);
  5969. return;
  5970. }
  5971. for (i = 0; i < pg->total; i++)
  5972. {
  5973. if (service == NULL)
  5974. {
  5975. if (pg->peers[i].daemon->running == GNUNET_YES)
  5976. {
  5977. GNUNET_assert (running != -1);
  5978. running++;
  5979. }
  5980. else
  5981. {
  5982. GNUNET_assert (stopped != -1);
  5983. stopped++;
  5984. }
  5985. }
  5986. else
  5987. {
  5988. /* FIXME: make churned services a list! */
  5989. pos = pg->peers[i].daemon->churned_services;
  5990. /* FIXME: while (pos != NULL) */
  5991. if (pos != NULL)
  5992. {
  5993. #if FIXME
  5994. if (0 == strcasecmp(pos, service))
  5995. {
  5996. break;
  5997. }
  5998. #endif
  5999. GNUNET_assert (stopped != -1);
  6000. stopped++;
  6001. /* FIXME: pos = pos->next; */
  6002. }
  6003. if (pos == NULL)
  6004. {
  6005. GNUNET_assert (running != -1);
  6006. running++;
  6007. }
  6008. }
  6009. }
  6010. if (voff > running)
  6011. {
  6012. GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
  6013. "Trying to stop more peers (%d) than are currently running (%d)!\n", voff, running);
  6014. cb (cb_cls, "Trying to stop more peers than are currently running!");
  6015. return;
  6016. }
  6017. if (von > stopped)
  6018. {
  6019. GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
  6020. "Trying to start more peers (%d) than are currently stopped (%d)!\n", von, stopped);
  6021. cb (cb_cls, "Trying to start more peers than are currently stopped!");
  6022. return;
  6023. }
  6024. churn_ctx = GNUNET_malloc (sizeof (struct ChurnContext));
  6025. if (service != NULL)
  6026. churn_ctx->service = GNUNET_strdup(service);
  6027. running_arr = NULL;
  6028. if (running > 0)
  6029. running_arr = GNUNET_malloc (running * sizeof (unsigned int));
  6030. stopped_arr = NULL;
  6031. if (stopped > 0)
  6032. stopped_arr = GNUNET_malloc (stopped * sizeof (unsigned int));
  6033. running_permute = NULL;
  6034. stopped_permute = NULL;
  6035. if (running > 0)
  6036. running_permute = GNUNET_CRYPTO_random_permute (GNUNET_CRYPTO_QUALITY_WEAK,
  6037. running);
  6038. if (stopped > 0)
  6039. stopped_permute = GNUNET_CRYPTO_random_permute (GNUNET_CRYPTO_QUALITY_WEAK,
  6040. stopped);
  6041. total_running = running;
  6042. total_stopped = stopped;
  6043. running = 0;
  6044. stopped = 0;
  6045. churn_ctx->num_to_start = von;
  6046. churn_ctx->num_to_stop = voff;
  6047. churn_ctx->cb = cb;
  6048. churn_ctx->cb_cls = cb_cls;
  6049. churn_ctx->pg = pg;
  6050. for (i = 0; i < pg->total; i++)
  6051. {
  6052. if (service == NULL)
  6053. {
  6054. if (pg->peers[i].daemon->running == GNUNET_YES)
  6055. {
  6056. GNUNET_assert ((running_arr != NULL) && (total_running > running));
  6057. running_arr[running] = i;
  6058. running++;
  6059. }
  6060. else
  6061. {
  6062. GNUNET_assert ((stopped_arr != NULL) && (total_stopped > stopped));
  6063. stopped_arr[stopped] = i;
  6064. stopped++;
  6065. }
  6066. }
  6067. else
  6068. {
  6069. /* FIXME: make churned services a list! */
  6070. pos = pg->peers[i].daemon->churned_services;
  6071. /* FIXME: while (pos != NULL) */
  6072. if (pos != NULL)
  6073. {
  6074. GNUNET_assert ((stopped_arr != NULL) && (total_stopped > stopped));
  6075. stopped_arr[stopped] = i;
  6076. stopped++;
  6077. /* FIXME: pos = pos->next; */
  6078. }
  6079. if (pos == NULL)
  6080. {
  6081. GNUNET_assert ((running_arr != NULL) && (total_running > running));
  6082. running_arr[running] = i;
  6083. running++;
  6084. }
  6085. }
  6086. }
  6087. GNUNET_assert (running >= voff);
  6088. if (voff > 0)
  6089. {
  6090. shutdown_ctx = GNUNET_malloc (sizeof (struct ShutdownContext));
  6091. shutdown_ctx->cb = &churn_stop_callback;
  6092. shutdown_ctx->cb_cls = churn_ctx;
  6093. shutdown_ctx->total_peers = voff;
  6094. shutdown_ctx->timeout = timeout;
  6095. }
  6096. for (i = 0; i < voff; i++)
  6097. {
  6098. #if DEBUG_CHURN
  6099. GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Stopping peer %d!\n", running_arr[running_permute[i]]);
  6100. #endif
  6101. GNUNET_assert (running_arr != NULL);
  6102. peer_shutdown_ctx = GNUNET_malloc (sizeof (struct PeerShutdownContext));
  6103. peer_shutdown_ctx->daemon
  6104. = pg->peers[running_arr[running_permute[i]]].daemon;
  6105. peer_shutdown_ctx->shutdown_ctx = shutdown_ctx;
  6106. GNUNET_SCHEDULER_add_now (&schedule_churn_shutdown_task,
  6107. peer_shutdown_ctx);
  6108. }
  6109. GNUNET_assert (stopped >= von);
  6110. if (von > 0)
  6111. {
  6112. churn_startup_ctx = GNUNET_malloc (sizeof (struct ChurnRestartContext));
  6113. churn_startup_ctx->churn_ctx = churn_ctx;
  6114. churn_startup_ctx->timeout = timeout;
  6115. churn_startup_ctx->pg = pg;
  6116. }
  6117. for (i = 0; i < von; i++)
  6118. {
  6119. #if DEBUG_CHURN
  6120. GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Starting up peer %d!\n", stopped_arr[stopped_permute[i]]);
  6121. #endif
  6122. GNUNET_assert (stopped_arr != NULL);
  6123. peer_restart_ctx = GNUNET_malloc (sizeof (struct PeerRestartContext));
  6124. peer_restart_ctx->churn_restart_ctx = churn_startup_ctx;
  6125. peer_restart_ctx->daemon
  6126. = pg->peers[stopped_arr[stopped_permute[i]]].daemon;
  6127. GNUNET_SCHEDULER_add_now (&schedule_churn_restart, peer_restart_ctx);
  6128. }
  6129. GNUNET_free_non_null (running_arr);
  6130. GNUNET_free_non_null (stopped_arr);
  6131. GNUNET_free_non_null (running_permute);
  6132. GNUNET_free_non_null (stopped_permute);
  6133. }
  6134. /*
  6135. * Start a given service for each of the peers in the peer group.
  6136. *
  6137. * @param pg handle for the peer group
  6138. * @param service the service to start
  6139. * @param timeout how long to wait for operations to finish before
  6140. * giving up
  6141. * @param cb function to call once finished
  6142. * @param cb_cls closure for cb
  6143. *
  6144. */
  6145. void
  6146. GNUNET_TESTING_daemons_start_service (struct GNUNET_TESTING_PeerGroup *pg,
  6147. char *service,
  6148. struct GNUNET_TIME_Relative timeout,
  6149. GNUNET_TESTING_NotifyCompletion cb,
  6150. void *cb_cls)
  6151. {
  6152. struct ServiceStartContext *start_ctx;
  6153. struct PeerServiceStartContext *peer_start_ctx;
  6154. unsigned int i;
  6155. GNUNET_assert(service != NULL);
  6156. start_ctx = GNUNET_malloc(sizeof(struct ServiceStartContext));
  6157. start_ctx->pg = pg;
  6158. start_ctx->remaining = pg->total;
  6159. start_ctx->cb = cb;
  6160. start_ctx->cb_cls = cb_cls;
  6161. start_ctx->service = GNUNET_strdup(service);
  6162. start_ctx->timeout = timeout;
  6163. for (i = 0; i < pg->total; i++)
  6164. {
  6165. #if DEBUG_START
  6166. GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Starting up service %s on peer %d!\n", service, stopped_arr[stopped_permute[i]]);
  6167. #endif
  6168. peer_start_ctx = GNUNET_malloc (sizeof (struct PeerServiceStartContext));
  6169. peer_start_ctx->start_ctx = start_ctx;
  6170. peer_start_ctx->daemon = pg->peers[i].daemon;
  6171. GNUNET_SCHEDULER_add_now (&schedule_service_start, peer_start_ctx);
  6172. }
  6173. }
  6174. /**
  6175. * Restart all peers in the given group.
  6176. *
  6177. * @param pg the handle to the peer group
  6178. * @param callback function to call on completion (or failure)
  6179. * @param callback_cls closure for the callback function
  6180. */
  6181. void
  6182. GNUNET_TESTING_daemons_restart(struct GNUNET_TESTING_PeerGroup *pg,
  6183. GNUNET_TESTING_NotifyCompletion callback,
  6184. void *callback_cls)
  6185. {
  6186. struct RestartContext *restart_context;
  6187. unsigned int off;
  6188. if (pg->total > 0)
  6189. {
  6190. restart_context = GNUNET_malloc (sizeof (struct RestartContext));
  6191. restart_context->peer_group = pg;
  6192. restart_context->peers_restarted = 0;
  6193. restart_context->callback = callback;
  6194. restart_context->callback_cls = callback_cls;
  6195. for (off = 0; off < pg->total; off++)
  6196. {
  6197. GNUNET_TESTING_daemon_restart (pg->peers[off].daemon,
  6198. &restart_callback, restart_context);
  6199. }
  6200. }
  6201. }
  6202. /**
  6203. * Start or stop an individual peer from the given group.
  6204. *
  6205. * @param pg handle to the peer group
  6206. * @param offset which peer to start or stop
  6207. * @param desired_status GNUNET_YES to have it running, GNUNET_NO to stop it
  6208. * @param timeout how long to wait for shutdown
  6209. * @param cb function to call at the end
  6210. * @param cb_cls closure for cb
  6211. */
  6212. void
  6213. GNUNET_TESTING_daemons_vary(struct GNUNET_TESTING_PeerGroup *pg,
  6214. unsigned int offset, int desired_status,
  6215. struct GNUNET_TIME_Relative timeout,
  6216. GNUNET_TESTING_NotifyCompletion cb, void *cb_cls)
  6217. {
  6218. struct ShutdownContext *shutdown_ctx;
  6219. struct ChurnRestartContext *startup_ctx;
  6220. struct ChurnContext *churn_ctx;
  6221. if (GNUNET_NO == desired_status)
  6222. {
  6223. if (NULL != pg->peers[offset].daemon)
  6224. {
  6225. shutdown_ctx = GNUNET_malloc (sizeof (struct ShutdownContext));
  6226. churn_ctx = GNUNET_malloc (sizeof (struct ChurnContext));
  6227. churn_ctx->num_to_start = 0;
  6228. churn_ctx->num_to_stop = 1;
  6229. churn_ctx->cb = cb;
  6230. churn_ctx->cb_cls = cb_cls;
  6231. shutdown_ctx->cb_cls = churn_ctx;
  6232. GNUNET_TESTING_daemon_stop (pg->peers[offset].daemon, timeout,
  6233. &churn_stop_callback, shutdown_ctx,
  6234. GNUNET_NO, GNUNET_YES);
  6235. }
  6236. }
  6237. else if (GNUNET_YES == desired_status)
  6238. {
  6239. if (NULL == pg->peers[offset].daemon)
  6240. {
  6241. startup_ctx = GNUNET_malloc (sizeof (struct ChurnRestartContext));
  6242. churn_ctx = GNUNET_malloc (sizeof (struct ChurnContext));
  6243. churn_ctx->num_to_start = 1;
  6244. churn_ctx->num_to_stop = 0;
  6245. churn_ctx->cb = cb;
  6246. churn_ctx->cb_cls = cb_cls;
  6247. startup_ctx->churn_ctx = churn_ctx;
  6248. GNUNET_TESTING_daemon_start_stopped (pg->peers[offset].daemon,
  6249. timeout, &churn_start_callback,
  6250. startup_ctx);
  6251. }
  6252. }
  6253. else
  6254. GNUNET_break (0);
  6255. }
  6256. /**
  6257. * Callback for shutting down peers in a peer group.
  6258. *
  6259. * @param cls closure (struct ShutdownContext)
  6260. * @param emsg NULL on success
  6261. */
  6262. static void
  6263. internal_shutdown_callback(void *cls, const char *emsg)
  6264. {
  6265. struct PeerShutdownContext *peer_shutdown_ctx = cls;
  6266. struct ShutdownContext *shutdown_ctx = peer_shutdown_ctx->shutdown_ctx;
  6267. unsigned int off;
  6268. struct OutstandingSSH *ssh_pos;
  6269. shutdown_ctx->outstanding--;
  6270. if (peer_shutdown_ctx->daemon->hostname != NULL)
  6271. decrement_outstanding_at_host (peer_shutdown_ctx->daemon->hostname,
  6272. shutdown_ctx->pg);
  6273. if (emsg == NULL)
  6274. {
  6275. shutdown_ctx->peers_down++;
  6276. }
  6277. else
  6278. {
  6279. shutdown_ctx->peers_failed++;
  6280. }
  6281. if ((shutdown_ctx->cb != NULL) && (shutdown_ctx->peers_down
  6282. + shutdown_ctx->peers_failed == shutdown_ctx->total_peers))
  6283. {
  6284. if (shutdown_ctx->peers_failed > 0)
  6285. shutdown_ctx->cb (shutdown_ctx->cb_cls,
  6286. "Not all peers successfully shut down!");
  6287. else
  6288. shutdown_ctx->cb (shutdown_ctx->cb_cls, NULL);
  6289. GNUNET_free (shutdown_ctx->pg->peers);
  6290. GNUNET_free_non_null(shutdown_ctx->pg->hostkey_data);
  6291. for (off = 0; off < shutdown_ctx->pg->num_hosts; off++)
  6292. {
  6293. GNUNET_free (shutdown_ctx->pg->hosts[off].hostname);
  6294. GNUNET_free_non_null (shutdown_ctx->pg->hosts[off].username);
  6295. }
  6296. GNUNET_free_non_null (shutdown_ctx->pg->hosts);
  6297. while (NULL != (ssh_pos = shutdown_ctx->pg->ssh_head))
  6298. {
  6299. GNUNET_CONTAINER_DLL_remove(shutdown_ctx->pg->ssh_head, shutdown_ctx->pg->ssh_tail, ssh_pos);
  6300. GNUNET_free(ssh_pos);
  6301. }
  6302. GNUNET_free (shutdown_ctx->pg);
  6303. GNUNET_free (shutdown_ctx);
  6304. }
  6305. GNUNET_free(peer_shutdown_ctx);
  6306. }
  6307. /**
  6308. * Task to rate limit the number of outstanding peer shutdown
  6309. * requests. This is necessary for making sure we don't do
  6310. * too many ssh connections at once, but is generally nicer
  6311. * to any system as well (graduated task starts, as opposed
  6312. * to calling gnunet-arm N times all at once).
  6313. */
  6314. static void
  6315. schedule_shutdown_task(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
  6316. {
  6317. struct PeerShutdownContext *peer_shutdown_ctx = cls;
  6318. struct ShutdownContext *shutdown_ctx;
  6319. GNUNET_assert (peer_shutdown_ctx != NULL);
  6320. shutdown_ctx = peer_shutdown_ctx->shutdown_ctx;
  6321. GNUNET_assert (shutdown_ctx != NULL);
  6322. if ((shutdown_ctx->outstanding < shutdown_ctx->pg->max_concurrent_ssh)
  6323. || ((peer_shutdown_ctx->daemon->hostname != NULL)
  6324. && (count_outstanding_at_host (peer_shutdown_ctx->daemon->hostname,
  6325. shutdown_ctx->pg)
  6326. < shutdown_ctx->pg->max_concurrent_ssh)))
  6327. {
  6328. if (peer_shutdown_ctx->daemon->hostname != NULL)
  6329. increment_outstanding_at_host (peer_shutdown_ctx->daemon->hostname,
  6330. shutdown_ctx->pg);
  6331. shutdown_ctx->outstanding++;
  6332. GNUNET_TESTING_daemon_stop (peer_shutdown_ctx->daemon,
  6333. shutdown_ctx->timeout,
  6334. &internal_shutdown_callback, peer_shutdown_ctx,
  6335. shutdown_ctx->delete_files, GNUNET_NO);
  6336. }
  6337. else
  6338. GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS,
  6339. 100),
  6340. &schedule_shutdown_task, peer_shutdown_ctx);
  6341. }
  6342. /**
  6343. * Read a testing hosts file based on a configuration.
  6344. * Returns a DLL of hosts (caller must free!) on success
  6345. * or NULL on failure.
  6346. *
  6347. * @param cfg a configuration with a testing section
  6348. *
  6349. * @return DLL of hosts on success, NULL on failure
  6350. */
  6351. struct GNUNET_TESTING_Host *
  6352. GNUNET_TESTING_hosts_load (const struct GNUNET_CONFIGURATION_Handle *cfg)
  6353. {
  6354. struct GNUNET_TESTING_Host *hosts;
  6355. struct GNUNET_TESTING_Host *temphost;
  6356. char *data;
  6357. char *buf;
  6358. char *hostfile;
  6359. struct stat frstat;
  6360. int count;
  6361. int ret;
  6362. /* Check for a hostfile containing user@host:port triples */
  6363. if (GNUNET_OK
  6364. != GNUNET_CONFIGURATION_get_value_string (cfg, "testing", "hostfile",
  6365. &hostfile))
  6366. return NULL;
  6367. hosts = NULL;
  6368. temphost = NULL;
  6369. data = NULL;
  6370. if (hostfile != NULL)
  6371. {
  6372. if (GNUNET_OK != GNUNET_DISK_file_test (hostfile))
  6373. GNUNET_DISK_fn_write (hostfile, NULL, 0, GNUNET_DISK_PERM_USER_READ
  6374. | GNUNET_DISK_PERM_USER_WRITE);
  6375. if ((0 != STAT (hostfile, &frstat)) || (frstat.st_size == 0))
  6376. {
  6377. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  6378. "Could not open file specified for host list, ending test!");
  6379. GNUNET_free(hostfile);
  6380. return NULL;
  6381. }
  6382. data = GNUNET_malloc_large (frstat.st_size);
  6383. GNUNET_assert(data != NULL);
  6384. if (frstat.st_size
  6385. != GNUNET_DISK_fn_read (hostfile, data, frstat.st_size))
  6386. {
  6387. GNUNET_log (
  6388. GNUNET_ERROR_TYPE_ERROR,
  6389. "Could not read file %s specified for host list, ending test!",
  6390. hostfile);
  6391. GNUNET_free (hostfile);
  6392. GNUNET_free (data);
  6393. return NULL;
  6394. }
  6395. GNUNET_free_non_null(hostfile);
  6396. buf = data;
  6397. count = 0;
  6398. while (count < frstat.st_size - 1)
  6399. {
  6400. count++;
  6401. if (((data[count] == '\n')) && (buf != &data[count]))
  6402. {
  6403. data[count] = '\0';
  6404. temphost = GNUNET_malloc(sizeof(struct GNUNET_TESTING_Host));
  6405. ret = sscanf (buf, "%a[a-zA-Z0-9_]@%a[a-zA-Z0-9.]:%hd",
  6406. &temphost->username, &temphost->hostname,
  6407. &temphost->port);
  6408. if (3 == ret)
  6409. {
  6410. GNUNET_log (
  6411. GNUNET_ERROR_TYPE_DEBUG,
  6412. "Successfully read host %s, port %d and user %s from file\n",
  6413. temphost->hostname, temphost->port,
  6414. temphost->username);
  6415. }
  6416. else
  6417. {
  6418. GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
  6419. "Error reading line `%s' in hostfile\n", buf);
  6420. GNUNET_free(temphost);
  6421. buf = &data[count + 1];
  6422. continue;
  6423. }
  6424. temphost->next = hosts;
  6425. hosts = temphost;
  6426. buf = &data[count + 1];
  6427. }
  6428. else if ((data[count] == '\n') || (data[count] == '\0'))
  6429. buf = &data[count + 1];
  6430. }
  6431. }
  6432. GNUNET_free_non_null(data);
  6433. return hosts;
  6434. }
  6435. /**
  6436. * Shutdown all peers started in the given group.
  6437. *
  6438. * @param pg handle to the peer group
  6439. * @param timeout how long to wait for shutdown
  6440. * @param cb callback to notify upon success or failure
  6441. * @param cb_cls closure for cb
  6442. */
  6443. void
  6444. GNUNET_TESTING_daemons_stop(struct GNUNET_TESTING_PeerGroup *pg,
  6445. struct GNUNET_TIME_Relative timeout,
  6446. GNUNET_TESTING_NotifyCompletion cb, void *cb_cls)
  6447. {
  6448. unsigned int off;
  6449. struct ShutdownContext *shutdown_ctx;
  6450. struct PeerShutdownContext *peer_shutdown_ctx;
  6451. #if OLD
  6452. struct PeerConnection *conn_iter;
  6453. struct PeerConnection *temp_conn;
  6454. #endif
  6455. GNUNET_assert (pg->total > 0);
  6456. shutdown_ctx = GNUNET_malloc (sizeof (struct ShutdownContext));
  6457. shutdown_ctx->delete_files = GNUNET_CONFIGURATION_get_value_yesno (pg->cfg,
  6458. "TESTING",
  6459. "DELETE_FILES");
  6460. shutdown_ctx->cb = cb;
  6461. shutdown_ctx->cb_cls = cb_cls;
  6462. shutdown_ctx->total_peers = pg->total;
  6463. shutdown_ctx->timeout = timeout;
  6464. shutdown_ctx->pg = pg;
  6465. /* shtudown_ctx->outstanding = 0; */
  6466. for (off = 0; off < pg->total; off++)
  6467. {
  6468. GNUNET_assert (NULL != pg->peers[off].daemon);
  6469. peer_shutdown_ctx = GNUNET_malloc (sizeof (struct PeerShutdownContext));
  6470. peer_shutdown_ctx->daemon = pg->peers[off].daemon;
  6471. peer_shutdown_ctx->shutdown_ctx = shutdown_ctx;
  6472. GNUNET_SCHEDULER_add_now (&schedule_shutdown_task, peer_shutdown_ctx);
  6473. if (NULL != pg->peers[off].cfg)
  6474. {
  6475. GNUNET_CONFIGURATION_destroy (pg->peers[off].cfg);
  6476. pg->peers[off].cfg = NULL;
  6477. }
  6478. #if OLD
  6479. conn_iter = pg->peers[off].allowed_peers_head;
  6480. while (conn_iter != NULL)
  6481. {
  6482. temp_conn = conn_iter->next;
  6483. GNUNET_free(conn_iter);
  6484. conn_iter = temp_conn;
  6485. }
  6486. conn_iter = pg->peers[off].connect_peers_head;
  6487. while (conn_iter != NULL)
  6488. {
  6489. temp_conn = conn_iter->next;
  6490. GNUNET_free(conn_iter);
  6491. conn_iter = temp_conn;
  6492. }
  6493. conn_iter = pg->peers[off].blacklisted_peers_head;
  6494. while (conn_iter != NULL)
  6495. {
  6496. temp_conn = conn_iter->next;
  6497. GNUNET_free(conn_iter);
  6498. conn_iter = temp_conn;
  6499. }
  6500. conn_iter = pg->peers[off].connect_peers_working_set_head;
  6501. while (conn_iter != NULL)
  6502. {
  6503. temp_conn = conn_iter->next;
  6504. GNUNET_free(conn_iter);
  6505. conn_iter = temp_conn;
  6506. }
  6507. #else
  6508. if (pg->peers[off].allowed_peers != NULL)
  6509. GNUNET_CONTAINER_multihashmap_destroy (pg->peers[off].allowed_peers);
  6510. if (pg->peers[off].connect_peers != NULL)
  6511. GNUNET_CONTAINER_multihashmap_destroy (pg->peers[off].connect_peers);
  6512. if (pg->peers[off].blacklisted_peers != NULL)
  6513. GNUNET_CONTAINER_multihashmap_destroy (pg->
  6514. peers[off].blacklisted_peers);
  6515. #endif
  6516. }
  6517. }
  6518. /* end of testing_group.c */