| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024 |
- // Copyright (c) 2004-2013 Sergey Lyubka
- // Copyright (c) 2013-2025 Cesanta Software Limited
- // All rights reserved
- //
- // This software is dual-licensed: you can redistribute it and/or modify
- // it under the terms of the GNU General Public License version 2 as
- // published by the Free Software Foundation. For the terms of this
- // license, see http://www.gnu.org/licenses/
- //
- // You are free to use this software under the terms of the GNU General
- // Public License, but WITHOUT ANY WARRANTY; without even the implied
- // warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- // See the GNU General Public License for more details.
- //
- // Alternatively, you can license this software under a commercial
- // license, as set out in https://www.mongoose.ws/licensing/
- //
- // SPDX-License-Identifier: GPL-2.0-only or commercial
- #ifndef MONGOOSE_H
- #define MONGOOSE_H
- #define MG_VERSION "7.23"
- #ifdef __cplusplus
- extern "C" {
- #endif
- #define MG_ARCH_CUSTOM 0 // User creates its own mongoose_config.h
- #define MG_ARCH_UNIX 1 // Linux, BSD, Mac, ...
- #define MG_ARCH_WIN32 2 // Windows
- #define MG_ARCH_ESP32 3 // ESP32
- #define MG_ARCH_ESP8266 4 // ESP8266
- #define MG_ARCH_FREERTOS 5 // FreeRTOS <-- DEPRECATED !!!
- #define MG_ARCH_THREADX 6 // Eclipse ThreadX (former MS Azure RTOS)
- #define MG_ARCH_ZEPHYR 7 // Zephyr RTOS
- #define MG_ARCH_ARMGCC 8 // Plain ARM GCC
- #define MG_ARCH_CMSIS_RTOS1 9 // CMSIS-RTOS API v1 (Keil RTX)
- #define MG_ARCH_TIRTOS 10 // Texas Semi TI-RTOS
- #define MG_ARCH_PICOSDK 11 // Raspberry Pi Pico-SDK (RP2040, RP2350)
- #define MG_ARCH_ARMCC 12 // Keil MDK-Core with Configuration Wizard
- #define MG_ARCH_CMSIS_RTOS2 13 // CMSIS-RTOS API v2 (Keil RTX5, FreeRTOS)
- #define MG_ARCH_RTTHREAD 14 // RT-Thread RTOS
- #define MG_ARCH_ARMCGT 15 // Texas Semi ARM-CGT
- #define MG_ARCH_CUBE 16 // STM32Cube environment
- #define MG_ARCH_MCUXPRESSO 17 // MCUXpresso environment
- #define MG_ARCH_NEWLIB MG_ARCH_ARMGCC // Alias, deprecate in 2025
- #if !defined(MG_ARCH)
- #if defined(__unix__) || defined(__APPLE__)
- #define MG_ARCH MG_ARCH_UNIX
- #elif defined(_WIN32)
- #define MG_ARCH MG_ARCH_WIN32
- #endif
- #endif // !defined(MG_ARCH)
- #if !defined(MG_ARCH) || (MG_ARCH == MG_ARCH_CUSTOM)
- #include "mongoose_config.h" // keep this include
- #endif
- #if !defined(MG_ARCH)
- #error "MG_ARCH is not specified and we couldn't guess it. Define MG_ARCH=... in mongoose_config.h"
- #elif MG_ARCH == MG_ARCH_FREERTOS
- #error "MG_ARCH_FREERTOS has been deprecated, set MG_ARCH=your_build_environment and MG_ENABLE_FREERTOS=1 instead"
- #undef MG_ARCH // avoid errors piling up, provide a clean environment so the error above is seen
- #define MG_ARCH MG_ARCH_ARMGCC
- #define MG_ENABLE_FREERTOS 1
- #endif
- // http://esr.ibiblio.org/?p=5095
- #define MG_BIG_ENDIAN (*(uint16_t *) "\0\xff" < 0x100)
- #if MG_ARCH == MG_ARCH_ARMCGT
- #include <ctype.h>
- #include <errno.h>
- #include <stdarg.h>
- #include <stdbool.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <sys/types.h>
- #include <time.h>
- #define MG_PATH_MAX 100
- #define MG_ENABLE_DIRLIST 0
- #endif
- #if MG_ARCH == MG_ARCH_ARMGCC
- #define _POSIX_TIMERS
- #include <ctype.h>
- #if !defined(MG_ENABLE_LWIP) || !MG_ENABLE_LWIP
- #include <errno.h>
- #endif
- #include <stdarg.h>
- #include <stdbool.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <sys/stat.h>
- #include <sys/time.h>
- #include <sys/types.h>
- #include <time.h>
- #include <unistd.h>
- #define MG_PATH_MAX 100
- #define MG_ENABLE_DIRLIST 0
- #endif
- #if MG_ARCH == MG_ARCH_CUBE
- #include <ctype.h>
- #if !defined(MG_ENABLE_LWIP) || !MG_ENABLE_LWIP
- #include <errno.h>
- #endif
- #include <stdarg.h>
- #include <stdbool.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <sys/stat.h>
- #include <sys/time.h>
- #include <sys/types.h>
- #include <time.h>
- #include <unistd.h>
- // Cube-generated header, includes ST Cube HAL
- // NOTE: use angle brackets to prevent amalgamator ditching it
- #include <main.h>
- #ifndef MG_PATH_MAX
- #define MG_PATH_MAX 100
- #endif
- #ifndef MG_ENABLE_DIRLIST
- #define MG_ENABLE_DIRLIST 0
- #endif
- #ifndef MG_ENABLE_TCPIP
- #define MG_ENABLE_TCPIP 1 // Enable built-in TCP/IP stack
- #endif
- #if MG_ENABLE_TCPIP && !defined(MG_ENABLE_DRIVER_STM32F) && \
- !defined(MG_ENABLE_DRIVER_STM32H) && !defined(MG_ENABLE_DRIVER_STM32N) && \
- !defined(MG_ENABLE_DRIVER_CYW) && !defined(MG_ENABLE_DRIVER_CYW_SDIO) && \
- !defined(MG_ENABLE_DRIVER_ST67W6)
- #if defined(STM32F1) || defined(STM32F2) || defined(STM32F4) || defined(STM32F7)
- #define MG_ENABLE_DRIVER_STM32F 1
- #elif defined(STM32H5) || defined(STM32H7)
- #define MG_ENABLE_DRIVER_STM32H 1
- #elif defined(STM32N6)
- #define MG_ENABLE_DRIVER_STM32N 1
- #else
- #error Select a driver in mongoose_config.h
- #endif
- #endif
- #ifndef MG_TLS
- #define MG_TLS MG_TLS_BUILTIN
- #endif
- #if !defined(MG_OTA) && defined(STM32F1) || defined(STM32F2) || \
- defined(STM32F4) || defined(STM32F7)
- #define MG_OTA MG_OTA_STM32F
- #elif !defined(MG_OTA) && defined(STM32H5)
- #define MG_OTA MG_OTA_STM32H5
- #elif !defined(MG_OTA) && defined(STM32H7)
- #define MG_OTA MG_OTA_STM32H7
- #endif
- // OTA rollback timer via IWDG. Fixed 10 s hang-detection window (prescaler
- // /1024, LSI ~32 kHz: reload = 10 * 32000 / 1024 = 312). mg_ota_poll() feeds
- // the watchdog every 500 ms while in MG_OTA_TESTING state; if the event loop
- // hangs for 10 s, the IWDG fires and the device rolls back.
- // STM32H7 names the peripheral IWDG1; all others use IWDG.
- // The total evaluation period is set by MG_OTA_ROLLBACK_TIMEOUT_SECONDS.
- // STM32H7 names the watchdog peripheral IWDG1; all other families use IWDG.
- #if defined(IWDG1) && !defined(IWDG)
- #define MG_IWDG IWDG1
- #else
- #define MG_IWDG IWDG
- #endif
- // PR=6 → /256 prescaler, RLR=1250 → ~10 s at LSI 32 kHz.
- // Works on F4/F7/H5/H7; uses direct register writes so it is safe before HAL_Init().
- #ifndef MG_OTA_ROLLBACK_TIMER_START
- #define MG_OTA_ROLLBACK_TIMER_START() \
- do { \
- MG_IWDG->KR = 0xCCCCU; /* start + LSI */ \
- MG_IWDG->KR = 0x5555U; /* unlock PR/RLR */ \
- MG_IWDG->PR = 6U; /* /256 */ \
- MG_IWDG->RLR = 1250U; /* 10 s */ \
- while (MG_IWDG->SR & (IWDG_SR_PVU | IWDG_SR_RVU)) (void) 0; \
- MG_IWDG->KR = 0xAAAAU; /* reload */ \
- } while (0)
- #endif
- // Feed (reload) the IWDG. Called from mg_ota_poll() every 500 ms.
- #ifndef MG_OTA_ROLLBACK_TIMER_FEED
- #define MG_OTA_ROLLBACK_TIMER_FEED() (MG_IWDG->KR = 0xAAAAU)
- #endif
- // OTA state in a backup register that survives warm resets but clears on POR.
- // STATE_GET reads work without any setup. STATE_SET enables the RTC APB clock
- // and unlocks backup domain write access via direct register writes, so it is
- // safe to call from any context (before or after HAL_Init).
- // H5 (TAMP->BKP0R), H7 (RTC->BKP0R), F4/F7 (RTC->BKP0R).
- #ifndef MG_OTA_STATE_GET
- #if defined(PWR_DBPCR_DBP)
- #define MG_OTA_DBP_ENABLE() (PWR->DBPCR |= PWR_DBPCR_DBP)
- #elif defined(PWR_CR1_DBP)
- #define MG_OTA_DBP_ENABLE() (PWR->CR1 |= PWR_CR1_DBP)
- #else
- #define MG_OTA_DBP_ENABLE() (PWR->CR |= PWR_CR_DBP)
- #endif
- #if defined(TAMP)
- #define MG_OTA_STATE_GET() \
- (RCC->APB3ENR |= RCC_APB3ENR_RTCAPBEN, TAMP->BKP0R)
- #define MG_OTA_STATE_SET(v) \
- (RCC->APB3ENR |= RCC_APB3ENR_RTCAPBEN, MG_OTA_DBP_ENABLE(), \
- (TAMP->BKP0R = (uint32_t) (v)), TAMP->BKP0R)
- #elif defined(RCC_APB4ENR_RTCAPBEN)
- #define MG_OTA_STATE_GET() (RTC->BKP0R)
- #define MG_OTA_STATE_SET(v) \
- (RCC->APB4ENR |= RCC_APB4ENR_RTCAPBEN, MG_OTA_DBP_ENABLE(), \
- (RTC->BKP0R = (uint32_t) (v)))
- #else
- #define MG_OTA_STATE_GET() (RTC->BKP0R)
- #define MG_OTA_STATE_SET(v) \
- (RCC->APB1ENR |= RCC_APB1ENR_PWREN, MG_OTA_DBP_ENABLE(), \
- (RTC->BKP0R = (uint32_t) (v)))
- #endif
- #endif
- // use HAL-defined execute-in-ram section
- #ifndef MG_IRAM
- #define MG_IRAM __attribute__((section(".RamFunc")))
- #endif
- #ifndef MG_ETH_RAM
- #define MG_ETH_RAM __attribute__((section(".eth_ram")))
- #endif
- #ifndef HAL_ICACHE_MODULE_ENABLED
- #define HAL_ICACHE_IsEnabled() 0
- #define HAL_ICACHE_Enable() (void) 0
- #define HAL_ICACHE_Disable() (void) 0
- #endif
- #ifndef MG_SET_MAC_ADDRESS
- // Construct MAC address from UUID
- #define MGUID ((uint32_t *) UID_BASE) // Unique 96-bit chip ID
- #define MG_SET_MAC_ADDRESS(mac) \
- do { \
- int icache_enabled_ = HAL_ICACHE_IsEnabled(); \
- if (icache_enabled_) HAL_ICACHE_Disable(); \
- mac[0] = 42; \
- mac[1] = ((MGUID[0] >> 0) & 255) ^ ((MGUID[2] >> 19) & 255); \
- mac[2] = ((MGUID[0] >> 10) & 255) ^ ((MGUID[1] >> 10) & 255); \
- mac[3] = (MGUID[0] >> 19) & 255; \
- mac[4] = ((MGUID[1] >> 0) & 255) ^ ((MGUID[2] >> 10) & 255); \
- mac[5] = ((MGUID[2] >> 0) & 255) ^ ((MGUID[1] >> 19) & 255); \
- if (icache_enabled_) HAL_ICACHE_Enable(); \
- } while (0)
- #endif
- #endif
- #if MG_ARCH == MG_ARCH_ESP32
- #include <ctype.h>
- #include <dirent.h>
- #include <errno.h>
- #include <fcntl.h>
- #include <limits.h>
- #include <netdb.h>
- #include <stdarg.h>
- #include <stddef.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <sys/stat.h>
- #include <sys/types.h>
- #include <time.h>
- #include <esp_ota_ops.h> // Use angle brackets to avoid
- #include <esp_timer.h> // amalgamation ditching them
- #include <esp_system.h>
- #include <esp_mac.h>
- #include <esp_idf_version.h>
- #include <esp_ota_ops.h>
- #include <esp_task_wdt.h>
- #include <soc/soc.h>
- #include <soc/rtc_cntl_reg.h>
- #define MG_PATH_MAX 128
- #ifndef MG_ENABLE_POSIX_FS
- #define MG_ENABLE_POSIX_FS 1
- #endif
- #ifndef MG_ENABLE_DIRLIST
- #define MG_ENABLE_DIRLIST 1
- #endif
- #ifndef MG_OTA_ESP32_WDT_TIMEOUT_MS
- #define MG_OTA_ESP32_WDT_TIMEOUT_MS 10000U
- #endif
- static inline void mg_ota_esp32_timer_start(void) {
- #if ESP_IDF_VERSION_MAJOR >= 5
- esp_task_wdt_config_t cfg = {0};
- esp_err_t err;
- cfg.timeout_ms = MG_OTA_ESP32_WDT_TIMEOUT_MS;
- cfg.idle_core_mask = 0;
- cfg.trigger_panic = true;
- err = esp_task_wdt_init(&cfg);
- if (err == ESP_ERR_INVALID_STATE) esp_task_wdt_reconfigure(&cfg);
- #else
- esp_task_wdt_init(MG_OTA_ESP32_WDT_TIMEOUT_MS / 1000U, true);
- #endif
- esp_task_wdt_add(NULL);
- esp_task_wdt_reset();
- }
- static inline uint32_t mg_ota_esp32_state_set(uint32_t state) {
- if (state == 0) esp_ota_mark_app_valid_cancel_rollback();
- REG_WRITE(RTC_CNTL_STORE0_REG, state);
- return REG_READ(RTC_CNTL_STORE0_REG);
- }
- #define MG_OTA_STATE_GET() \
- REG_READ(RTC_CNTL_STORE0_REG)
- #define MG_OTA_STATE_SET(v) mg_ota_esp32_state_set((uint32_t) (v))
- #ifndef MG_OTA_ROLLBACK_TIMER_START
- #define MG_OTA_ROLLBACK_TIMER_START() mg_ota_esp32_timer_start()
- #endif
- #ifndef MG_OTA_ROLLBACK_TIMER_FEED
- #define MG_OTA_ROLLBACK_TIMER_FEED() \
- do { \
- (void) esp_task_wdt_reset(); \
- } while (0)
- #endif
- #ifndef MG_OTA_ROLLBACK
- #define MG_OTA_ROLLBACK() \
- do { \
- (void) esp_ota_mark_app_invalid_rollback_and_reboot(); \
- } while (0)
- #endif
- #endif
- #if MG_ARCH == MG_ARCH_ESP8266
- #include <ctype.h>
- #include <dirent.h>
- #include <errno.h>
- #include <fcntl.h>
- #include <limits.h>
- #include <netdb.h>
- #include <stdarg.h>
- #include <stdbool.h>
- #include <stddef.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <sys/stat.h>
- #include <sys/time.h>
- #include <sys/types.h>
- #include <time.h>
- #include <esp_system.h>
- #define MG_PATH_MAX 128
- #endif
- #if MG_ARCH == MG_ARCH_MCUXPRESSO
- #define _POSIX_TIMERS
- #include <ctype.h>
- #if !defined(MG_ENABLE_LWIP) || !MG_ENABLE_LWIP
- #include <errno.h>
- #endif
- #include <stdarg.h>
- #include <stdbool.h>
- #include <stdint.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <sys/stat.h>
- #include <sys/time.h>
- #include <sys/types.h>
- #include <time.h>
- #include <unistd.h>
- // MCUXpresso-generated header, includes the SoC peripheral definitions.
- // NOTE: use angle brackets to prevent amalgamator ditching it
- #include <fsl_device_registers.h>
- #ifndef MG_PATH_MAX
- #define MG_PATH_MAX 100
- #endif
- #ifndef MG_ENABLE_DIRLIST
- #define MG_ENABLE_DIRLIST 0
- #endif
- #ifndef MG_ENABLE_TCPIP
- #define MG_ENABLE_TCPIP 1 // Enable built-in TCP/IP stack
- #endif
- #if MG_ENABLE_TCPIP && !defined(MG_ENABLE_DRIVER_IMXRT10) && \
- !defined(MG_ENABLE_DRIVER_IMXRT11)
- #if defined(CPU_MIMXRT1021DAG5A) || defined(CPU_MIMXRT1024DAG5A) || \
- defined(CPU_MIMXRT1042XJM5B) || defined(CPU_MIMXRT1052DVL6B) || \
- defined(CPU_MIMXRT1062DVL6B) || defined(CPU_MIMXRT1064DVL6B) || \
- defined(CPU_MIMXRT1062DVL6A) || defined(CPU_MIMXRT1064DVL6A) || \
- defined(CPU_MIMXRT1062DVMAA_cm7) || defined(CPU_MIMXRT1062DVL6A_cm7) || \
- defined(CPU_MIMXRT1062DVL6B_cm7) || defined(_MIMXRT1021_H_) || \
- defined(_MIMXRT1024_H_) || defined(_MIMXRT1042_H_) || \
- defined(_MIMXRT1052_H_) || defined(_MIMXRT1062_H_) || \
- defined(_MIMXRT1064_H_)
- #define MG_ENABLE_DRIVER_IMXRT10 1
- #elif defined(CPU_MIMXRT1176DVMAA_cm7) || defined(CPU_MIMXRT1176DVMAA_cm4) || \
- defined(_MIMXRT1176_cm7_H_) || defined(_MIMXRT1176_cm4_H_) || \
- defined(_MIMXRT1176_H_)
- #define MG_ENABLE_DRIVER_IMXRT11 1
- #else
- #error Select an Ethernet driver in mongoose_config.h
- #endif
- #endif
- #ifndef MG_TLS
- #define MG_TLS MG_TLS_BUILTIN
- #endif
- #if !defined(MG_OTA) && \
- (defined(CPU_MIMXRT1021DAG5A) || defined(CPU_MIMXRT1024DAG5A) || \
- defined(_MIMXRT1021_H_) || defined(_MIMXRT1024_H_))
- #define MG_OTA MG_OTA_RT1020
- #elif !defined(MG_OTA) && \
- (defined(CPU_MIMXRT1052DVL6B) || defined(_MIMXRT1052_H_))
- #define MG_OTA MG_OTA_RT1050
- #elif !defined(MG_OTA) && \
- (defined(CPU_MIMXRT1062DVL6B) || defined(CPU_MIMXRT1062DVL6A) || \
- defined(CPU_MIMXRT1042XJM5B) || defined(_MIMXRT1042_H_) || \
- defined(CPU_MIMXRT1062DVMAA_cm7) || defined(CPU_MIMXRT1062DVL6A_cm7) || \
- defined(CPU_MIMXRT1062DVL6B_cm7) || defined(_MIMXRT1062_H_))
- #define MG_OTA MG_OTA_RT1060
- #elif !defined(MG_OTA) && \
- (defined(CPU_MIMXRT1064DVL6B) || defined(CPU_MIMXRT1064DVL6A) || \
- defined(_MIMXRT1064_H_))
- #define MG_OTA MG_OTA_RT1064
- #elif !defined(MG_OTA) && \
- (defined(CPU_MIMXRT1176DVMAA_cm7) || defined(CPU_MIMXRT1176DVMAA_cm4) || \
- defined(_MIMXRT1176_cm7_H_) || defined(_MIMXRT1176_cm4_H_) || \
- defined(_MIMXRT1176_H_))
- #define MG_OTA MG_OTA_RT1170
- #endif
- #ifndef MG_IRAM
- #define MG_IRAM __attribute__((noinline, section(".data_RAM2")))
- #endif
- #ifndef MG_SET_MAC_ADDRESS
- #if defined(MG_ENABLE_DRIVER_IMXRT11) && MG_ENABLE_DRIVER_IMXRT11
- #define MG_OCOTP_FUSES ((volatile uint32_t *) 0x40cac900)
- #else
- #define MG_OCOTP_FUSES ((volatile uint32_t *) 0x401f4410)
- #endif
- #define MG_SET_MAC_ADDRESS(mac) \
- do { \
- mac[0] = 2; \
- mac[1] = (MG_OCOTP_FUSES[0] >> 0) & 255; \
- mac[2] = (MG_OCOTP_FUSES[0] >> 10) & 255; \
- mac[3] = ((MG_OCOTP_FUSES[0] >> 19) ^ (MG_OCOTP_FUSES[4] >> 19)) & 255; \
- mac[4] = (MG_OCOTP_FUSES[4] >> 10) & 255; \
- mac[5] = (MG_OCOTP_FUSES[4] >> 0) & 255; \
- } while (0)
- #endif
- #ifndef MG_IMXRT_WDOG1_TIMEOUT_MS
- #define MG_IMXRT_WDOG1_TIMEOUT_MS 10000
- #endif
- #define MG_IMXRT_WDOG1_FEED() \
- do { \
- WDOG1->WSR = 0x5555; \
- WDOG1->WSR = 0xaaaa; \
- } while (0)
- #ifndef MG_OTA_ROLLBACK_TIMER_START
- #define MG_OTA_ROLLBACK_TIMER_START() \
- do { \
- uint16_t wt_ = (uint16_t) ((MG_IMXRT_WDOG1_TIMEOUT_MS / 500) - 1); \
- if ((WDOG1->WCR & WDOG_WCR_WDE_MASK) == 0) { \
- WDOG1->WMCR = 0; \
- WDOG1->WCR = (uint16_t) (WDOG_WCR_WDZST_MASK | WDOG_WCR_WDBG_MASK | \
- WDOG_WCR_WDE_MASK | WDOG_WCR_WDT_MASK | \
- WDOG_WCR_SRS_MASK | WDOG_WCR_WDW_MASK | \
- WDOG_WCR_WT(wt_)); \
- } \
- MG_IMXRT_WDOG1_FEED(); \
- } while (0)
- #endif
- #ifndef MG_OTA_ROLLBACK_TIMER_FEED
- #define MG_OTA_ROLLBACK_TIMER_FEED() MG_IMXRT_WDOG1_FEED()
- #endif
- #ifndef MG_OTA_STATE_GET
- #define MG_OTA_STATE_GET() SNVS->LPGPR[0]
- #endif
- #ifndef MG_OTA_STATE_SET
- #define MG_OTA_STATE_SET(v) \
- do { \
- if (SNVS->LPSR & (1u << 3)) { \
- SNVS->LPLVDR = 0x41736166u; \
- SNVS->LPSR = 1u << 3; \
- } \
- SNVS->LPGPR[0] = (uint32_t) (v); \
- } while (0)
- #endif
- #endif
- #if MG_ARCH == MG_ARCH_PICOSDK
- #if !defined(MG_ENABLE_LWIP) || !MG_ENABLE_LWIP
- #include <errno.h>
- #endif
- #include <stdarg.h>
- #include <stdbool.h>
- #include <stdint.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <time.h>
- #include <pico/stdlib.h>
- #include <pico/rand.h>
- #include <pico/unique_id.h>
- int mkdir(const char *, mode_t);
- #if MG_OTA == MG_OTA_PICOSDK
- #include <hardware/flash.h>
- #include <hardware/watchdog.h>
- #include <hardware/structs/watchdog.h>
- #include <pico/bootrom.h>
- #ifndef MG_OTA_WATCHDOG_MS
- #if PICO_RP2040
- #define MG_OTA_WATCHDOG_MS 8000U // max delay on RP2040 is 8.3 seconds
- #else
- #define MG_OTA_WATCHDOG_MS 10000U // max delay on RP2350 is 16 seconds
- #endif
- #endif
- #ifndef MG_OTA_ROLLBACK_TIMER_START
- #define MG_OTA_ROLLBACK_TIMER_START() watchdog_enable(MG_OTA_WATCHDOG_MS, false)
- #endif
- #ifndef MG_OTA_ROLLBACK_TIMER_FEED
- #define MG_OTA_ROLLBACK_TIMER_FEED() watchdog_update()
- #endif
- #define MG_OTA_STATE_GET() ((uint32_t) watchdog_hw->scratch[0])
- #define MG_OTA_STATE_SET(v) \
- (watchdog_hw->scratch[0] = (uint32_t) (v), (uint32_t) watchdog_hw->scratch[0])
- #if PICO_RP2040
- #define MG_OTA_ROLLBACK() \
- do { \
- mg_flash->swap_fn(); \
- *(volatile unsigned long *) 0xe000ed0c = 0x5fa0004; \
- } while (0)
- #else
- #define MG_OTA_ROLLBACK() \
- do { \
- mg_flash->swap_fn(); \
- ((rom_reboot_fn) rom_func_lookup(ROM_FUNC_REBOOT))( \
- BOOT_TYPE_NORMAL | 0x100, 1, 0, 0); \
- } while (0)
- #endif
- #endif
- #endif
- #if MG_ARCH == MG_ARCH_RTTHREAD
- #include <rtthread.h>
- #include <ctype.h>
- #include <errno.h>
- #include <fcntl.h>
- #include <sys/socket.h>
- #include <sys/select.h>
- #include <stdarg.h>
- #include <stdbool.h>
- #include <stdint.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <sys/types.h>
- #include <time.h>
- #ifndef MG_IO_SIZE
- #define MG_IO_SIZE 1460
- #endif
- #endif // MG_ARCH == MG_ARCH_RTTHREAD
- #if MG_ARCH == MG_ARCH_ARMCC || MG_ARCH == MG_ARCH_CMSIS_RTOS1 || \
- MG_ARCH == MG_ARCH_CMSIS_RTOS2
- #include <ctype.h>
- #include <errno.h>
- #include <stdarg.h>
- #include <stdbool.h>
- #include <stddef.h>
- #include <stdint.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <alloca.h>
- #include <string.h>
- #include <time.h>
- #if MG_ARCH == MG_ARCH_CMSIS_RTOS1
- #include "cmsis_os.h" // keep this include
- // https://developer.arm.com/documentation/ka003821/latest
- extern uint32_t rt_time_get(void);
- #elif MG_ARCH == MG_ARCH_CMSIS_RTOS2
- #include "cmsis_os2.h" // keep this include
- #endif
- #define strdup(s) ((char *) mg_strdup(mg_str(s)).buf)
- #if defined(__ARMCC_VERSION)
- #define mode_t size_t
- #if !defined(MG_ENABLE_POSIX_FS) || !MG_ENABLE_POSIX_FS
- #else
- #define mkdir(a, b) mg_mkdir(a, b)
- static inline int mg_mkdir(const char *path, mode_t mode) {
- (void) path, (void) mode;
- return -1;
- }
- #endif
- #endif
- #if (MG_ARCH == MG_ARCH_CMSIS_RTOS1 || MG_ARCH == MG_ARCH_CMSIS_RTOS2) && \
- !defined MG_ENABLE_RL && (!defined(MG_ENABLE_LWIP) || !MG_ENABLE_LWIP) && \
- (!defined(MG_ENABLE_TCPIP) || !MG_ENABLE_TCPIP)
- #define MG_ENABLE_RL 1
- #ifndef MG_SOCK_LISTEN_BACKLOG_SIZE
- #define MG_SOCK_LISTEN_BACKLOG_SIZE 3
- #endif
- #endif
- #endif
- #if MG_ARCH == MG_ARCH_THREADX
- #include <stdarg.h>
- #include <stdbool.h>
- #include <stdint.h>
- #include <string.h>
- // Do not include time.h and stdlib.h, since they conflict with nxd_bsd.h
- // extern time_t time(time_t *);
- #include <nxd_bsd.h>
- #define MG_DIRSEP '\\'
- #undef FOPEN_MAX
- #ifndef MG_PATH_MAX
- #define MG_PATH_MAX 32
- #endif
- #ifndef MG_SOCK_LISTEN_BACKLOG_SIZE
- #define MG_SOCK_LISTEN_BACKLOG_SIZE 3
- #endif
- #ifndef MG_ENABLE_IPV6
- #define MG_ENABLE_IPV6 0
- #endif
- #define socklen_t int
- #define closesocket(x) soc_close(x)
- // In order to enable BSD support in NetxDuo, do the following (assuming Cube):
- // 1. Add nxd_bsd.h and nxd_bsd.c to the repo:
- // https://github.com/eclipse-threadx/netxduo/blob/v6.1.12_rel/addons/BSD/nxd_bsd.c
- // https://github.com/eclipse-threadx/netxduo/blob/v6.1.12_rel/addons/BSD/nxd_bsd.h
- // 2. Add to tx_user.h
- // #define TX_THREAD_USER_EXTENSION int bsd_errno;
- // 3. Add to nx_user.h
- // #define NX_ENABLE_EXTENDED_NOTIFY_SUPPORT
- // 4. Add __CCRX__ build preprocessor constant
- // Project -> Properties -> C/C++ -> Settings -> MCU Compiler -> Preprocessor
- #endif
- #if MG_ARCH == MG_ARCH_TIRTOS
- #include <stdlib.h>
- #include <ctype.h>
- #include <stdarg.h>
- #include <stdbool.h>
- #include <stdint.h>
- #include <stdio.h>
- #include <string.h>
- #include <time.h>
- #include <serrno.h>
- #include <sys/socket.h>
- #include <ti/sysbios/knl/Clock.h>
- #endif
- #if MG_ARCH == MG_ARCH_UNIX
- #define _DARWIN_UNLIMITED_SELECT 1 // No limit on file descriptors
- #if defined(__APPLE__)
- #include <mach/mach_time.h>
- #endif
- #if !defined(MG_ENABLE_EPOLL) && defined(__linux__)
- #define MG_ENABLE_EPOLL 1
- #elif !defined(MG_ENABLE_POLL)
- #define MG_ENABLE_POLL 1
- #endif
- #include <arpa/inet.h>
- #include <ctype.h>
- #include <dirent.h>
- #if !defined(MG_ENABLE_LWIP) || !MG_ENABLE_LWIP
- #include <errno.h>
- #endif
- #include <fcntl.h>
- #include <inttypes.h>
- #include <limits.h>
- #include <netdb.h>
- #include <netinet/in.h>
- #include <netinet/tcp.h>
- #include <signal.h>
- #include <stdarg.h>
- #include <stdbool.h>
- #include <stddef.h>
- #include <stdint.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #if defined(MG_ENABLE_EPOLL) && MG_ENABLE_EPOLL
- #include <sys/epoll.h>
- #elif defined(MG_ENABLE_POLL) && MG_ENABLE_POLL
- #include <poll.h>
- #else
- #include <sys/select.h>
- #endif
- #include <sys/socket.h>
- #include <sys/stat.h>
- #include <sys/time.h>
- #include <sys/types.h>
- #include <time.h>
- #include <unistd.h>
- #ifndef MG_ENABLE_DIRLIST
- #define MG_ENABLE_DIRLIST 1
- #endif
- #ifndef MG_PATH_MAX
- #define MG_PATH_MAX FILENAME_MAX
- #endif
- #ifndef MG_ENABLE_POSIX_FS
- #define MG_ENABLE_POSIX_FS 1
- #endif
- #ifndef MG_IO_SIZE
- #define MG_IO_SIZE 16384
- #endif
- #endif
- #if MG_ARCH == MG_ARCH_WIN32
- // Avoid name clashing; (macro expansion producing 'defined' has undefined
- // behaviour). See config.h for user options
- #ifndef MG_ENABLE_WINSOCK
- #if (!defined(MG_ENABLE_TCPIP) || !MG_ENABLE_TCPIP) && \
- (!defined(MG_ENABLE_LWIP) || !MG_ENABLE_LWIP) && \
- (!defined(MG_ENABLE_FREERTOS_TCP) || !MG_ENABLE_FREERTOS_TCP)
- #define MG_ENABLE_WINSOCK 1
- #else
- #define MG_ENABLE_WINSOCK 0
- #endif
- #endif
- #ifndef _CRT_RAND_S
- #define _CRT_RAND_S
- #endif
- #ifndef _WIN32_WINNT
- #if defined(_MSC_VER) && _MSC_VER < 1700
- #define _WIN32_WINNT 0x0400 // Let vc98 pick up wincrypt.h
- #else
- #define _WIN32_WINNT 0x0600
- #endif
- #endif
- #ifndef WINVER
- #define WINVER _WIN32_WINNT
- #endif
- #ifndef WIN32_LEAN_AND_MEAN
- #define WIN32_LEAN_AND_MEAN
- #endif
- #ifndef _CRT_SECURE_NO_WARNINGS
- #define _CRT_SECURE_NO_WARNINGS
- #endif
- #ifndef _WINSOCK_DEPRECATED_NO_WARNINGS
- #define _WINSOCK_DEPRECATED_NO_WARNINGS
- #endif
- #include <ctype.h>
- #include <direct.h>
- #if !defined(MG_ENABLE_LWIP) || !MG_ENABLE_LWIP
- #include <errno.h>
- #endif
- #include <fcntl.h>
- #include <limits.h>
- #include <signal.h>
- #include <stdarg.h>
- #include <stddef.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <sys/stat.h>
- #include <sys/types.h>
- #include <time.h>
- #include <winsock2.h> // fix missing macros and types
- #if defined(_MSC_VER) && _MSC_VER < 1700
- #define __func__ ""
- typedef __int64 int64_t;
- typedef unsigned __int64 uint64_t;
- typedef unsigned char uint8_t;
- typedef char int8_t;
- typedef unsigned short uint16_t;
- typedef short int16_t;
- typedef unsigned int uint32_t;
- typedef int int32_t;
- typedef enum { false = 0, true = 1 } bool;
- #define inline __inline
- #else
- #include <stdbool.h>
- #include <stdint.h>
- #if MG_ENABLE_WINSOCK
- #include <ws2tcpip.h>
- #endif
- #endif
- #include <process.h>
- #include <winerror.h>
- // For mg_random()
- #if defined(_MSC_VER) && _MSC_VER < 1700
- #include <wincrypt.h>
- #pragma comment(lib, "advapi32.lib")
- #endif
- #if defined(_MSC_VER) && _MSC_VER <= 1200
- #ifndef IPPROTO_IP
- #define IPPROTO_IP 0
- #endif
- #ifndef IP_ADD_MEMBERSHIP
- struct ip_mreq {
- struct in_addr imr_multiaddr;
- struct in_addr imr_interface;
- };
- #define IP_ADD_MEMBERSHIP 12
- #endif
- #endif
- // Protect from calls like std::snprintf in app code
- // See https://github.com/cesanta/mongoose/issues/1047
- #ifndef __cplusplus
- #define snprintf _snprintf
- #define vsnprintf _vsnprintf
- #ifndef strdup // For MSVC with _DEBUG, see #1359
- #define strdup(x) _strdup(x)
- #endif
- #endif
- #if defined(MG_ENABLE_POLL) && MG_ENABLE_POLL && (!defined(MG_ENABLE_LWIP) || !MG_ENABLE_LWIP)
- typedef unsigned long nfds_t; // see #3388
- #endif
- #if defined(_MSC_VER)
- #if MG_ENABLE_WINSOCK
- #pragma comment(lib, "ws2_32.lib")
- #endif
- #ifndef alloca
- #define alloca(a) _alloca(a)
- #endif
- #endif
- #define MG_DIRSEP '\\'
- #ifndef MG_PATH_MAX
- #define MG_PATH_MAX FILENAME_MAX
- #endif
- #if MG_ENABLE_WINSOCK
- #define MG_INVALID_SOCKET INVALID_SOCKET
- #define MG_SOCKET_TYPE SOCKET
- #define poll(a, b, c) WSAPoll((a), (b), (c))
- #define closesocket(x) closesocket(x)
- typedef int socklen_t;
- #ifndef SO_EXCLUSIVEADDRUSE
- #define SO_EXCLUSIVEADDRUSE ((int) (~SO_REUSEADDR))
- #endif
- #define MG_SOCK_ERR(errcode) ((errcode) < 0 ? WSAGetLastError() : 0)
- #define MG_SOCK_PENDING(errcode) \
- (((errcode) < 0) && \
- (WSAGetLastError() == WSAEINTR || WSAGetLastError() == WSAEINPROGRESS || \
- WSAGetLastError() == WSAEWOULDBLOCK))
- #define MG_SOCK_RESET(errcode) \
- (((errcode) < 0) && (WSAGetLastError() == WSAECONNRESET))
- #endif // MG_ENABLE_WINSOCK
- #define realpath(a, b) _fullpath((b), (a), MG_PATH_MAX)
- #define sleep(x) Sleep((x) *1000)
- #define mkdir(a, b) _mkdir(a)
- #define rmdir(a) _rmdir(a)
- #define timegm(x) _mkgmtime(x)
- #ifndef S_ISDIR
- #define S_ISDIR(x) (((x) &_S_IFMT) == _S_IFDIR)
- #endif
- #ifndef MG_ENABLE_DIRLIST
- #define MG_ENABLE_DIRLIST 1
- #endif
- #ifndef SIGPIPE
- #define SIGPIPE 0
- #endif
- #ifndef MG_ENABLE_POSIX_FS
- #define MG_ENABLE_POSIX_FS 1
- #endif
- #ifndef MG_IO_SIZE
- #define MG_IO_SIZE 16384
- #endif
- #endif
- #if MG_ARCH == MG_ARCH_ZEPHYR
- #include <zephyr/kernel.h>
- #include <zephyr/net/socket.h>
- // #include <zephyr/posix/dirent.h>
- #include <zephyr/posix/fcntl.h>
- #include <zephyr/posix/sys/select.h>
- #include <zephyr/random/random.h>
- #include <zephyr/version.h>
- #include <ctype.h>
- #include <errno.h>
- #include <stdarg.h>
- #include <stdbool.h>
- #include <stdint.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <sys/types.h>
- #include <time.h>
- #define MG_PUTCHAR(x) printk("%c", x)
- #ifndef strdup
- #define strdup(s) ((char *) mg_strdup(mg_str(s)).buf)
- #endif
- #define strerror(x) zsock_gai_strerror(x)
- #ifndef FD_CLOEXEC
- #define FD_CLOEXEC 0
- #endif
- #ifndef F_SETFD
- #define F_SETFD 0
- #endif
- #define MG_ENABLE_SSI 0
- int rand(void);
- int sscanf(const char *, const char *, ...);
- #endif
- #if defined(MG_ENABLE_FREERTOS) && MG_ENABLE_FREERTOS
- #include <FreeRTOS.h>
- #include <task.h>
- #define MG_ENABLE_CUSTOM_CALLOC 1
- static inline void mg_free(void *ptr) {
- vPortFree(ptr);
- }
- // Re-route calloc/free to FreeRTOS functions, don't use stdlib
- static inline void *mg_calloc(size_t cnt, size_t size) {
- void *p = pvPortMalloc(cnt * size);
- if (p != NULL) memset(p, 0, size * cnt);
- return p;
- }
- #endif // MG_ENABLE_FREERTOS
- #if defined(MG_ENABLE_FREERTOS_TCP) && MG_ENABLE_FREERTOS_TCP
- #include <limits.h>
- #include <list.h>
- #include <FreeRTOS_IP.h>
- #include <FreeRTOS_Sockets.h>
- #define MG_SOCKET_TYPE Socket_t
- #define MG_INVALID_SOCKET FREERTOS_INVALID_SOCKET
- // Why FreeRTOS-TCP did not implement a clean BSD API, but its own thing
- // with FreeRTOS_ prefix, is beyond me
- #define IPPROTO_TCP FREERTOS_IPPROTO_TCP
- #define IPPROTO_UDP FREERTOS_IPPROTO_UDP
- #define AF_INET FREERTOS_AF_INET
- #define SOCK_STREAM FREERTOS_SOCK_STREAM
- #define SOCK_DGRAM FREERTOS_SOCK_DGRAM
- #define SO_BROADCAST 0
- #define SO_ERROR 0
- #define SOL_SOCKET 0
- #define SO_REUSEADDR 0
- #define MG_SOCK_ERR(errcode) ((errcode) < 0 ? (errcode) : 0)
- #define MG_SOCK_PENDING(errcode) \
- ((errcode) == -pdFREERTOS_ERRNO_EWOULDBLOCK || \
- (errcode) == -pdFREERTOS_ERRNO_EISCONN || \
- (errcode) == -pdFREERTOS_ERRNO_EINPROGRESS || \
- (errcode) == -pdFREERTOS_ERRNO_EAGAIN || \
- (errcode) == -pdFREERTOS_ERRNO_ENOSPC)
- #define MG_SOCK_RESET(errcode) ((errcode) == -pdFREERTOS_ERRNO_ENOTCONN)
- // actually only if optional timeout is enabled
- #define MG_SOCK_INTR(fd) (fd == NULL)
- #define sockaddr_in freertos_sockaddr
- #define sockaddr freertos_sockaddr
- #if ipFR_TCP_VERSION_MAJOR >= 4
- #define sin_addr sin_address.ulIP_IPv4
- #endif
- #define accept(a, b, c) FreeRTOS_accept((a), (b), (c))
- #define connect(a, b, c) FreeRTOS_connect((a), (b), (c))
- #define bind(a, b, c) FreeRTOS_bind((a), (b), (c))
- #define listen(a, b) FreeRTOS_listen((a), (b))
- #define socket(a, b, c) FreeRTOS_socket((a), (b), (c))
- #define send(a, b, c, d) FreeRTOS_send((a), (b), (c), (d))
- #define recv(a, b, c, d) FreeRTOS_recv((a), (b), (c), (d))
- #define setsockopt(a, b, c, d, e) FreeRTOS_setsockopt((a), (b), (c), (d), (e))
- #define sendto(a, b, c, d, e, f) FreeRTOS_sendto((a), (b), (c), (d), (e), (f))
- #define recvfrom(a, b, c, d, e, f) \
- FreeRTOS_recvfrom((a), (b), (c), (d), (e), (f))
- #define closesocket(x) FreeRTOS_closesocket(x)
- #define gethostbyname(x) FreeRTOS_gethostbyname(x)
- #define getsockname(a, b, c) mg_getsockname((a), (b), (c))
- #define getpeername(a, b, c) mg_getpeername((a), (b), (c))
- static inline int mg_getsockname(MG_SOCKET_TYPE fd, void *buf, socklen_t *len) {
- (void) fd, (void) buf, (void) len;
- return -1;
- }
- static inline int mg_getpeername(MG_SOCKET_TYPE fd, void *buf, socklen_t *len) {
- (void) fd, (void) buf, (void) len;
- return 0;
- }
- #endif
- #if defined(MG_ENABLE_LWIP) && MG_ENABLE_LWIP
- #if defined(__GNUC__) && !defined(__ARMCC_VERSION)
- #include <sys/stat.h>
- #endif
- struct timeval;
- #include <lwip/sockets.h>
- #if !LWIP_TIMEVAL_PRIVATE
- #if defined(__GNUC__) && !defined(__ARMCC_VERSION) // armclang sets both
- #include <sys/time.h>
- #else
- struct timeval {
- time_t tv_sec;
- long tv_usec;
- };
- #endif
- #endif
- #if LWIP_SOCKET != 1
- // Sockets support disabled in LWIP by default
- #error Set LWIP_SOCKET variable to 1 (in lwipopts.h)
- #endif
- #endif
- #if defined(MG_ENABLE_RL) && MG_ENABLE_RL
- #include <rl_net.h>
- #define closesocket(x) closesocket(x)
- #define TCP_NODELAY SO_KEEPALIVE
- #define MG_SOCK_ERR(errcode) ((errcode) < 0 ? (errcode) : 0)
- #define MG_SOCK_PENDING(errcode) \
- ((errcode) == BSD_EWOULDBLOCK || (errcode) == BSD_EALREADY || \
- (errcode) == BSD_EINPROGRESS)
- #define MG_SOCK_RESET(errcode) \
- ((errcode) == BSD_ECONNABORTED || (errcode) == BSD_ECONNRESET)
- // In blocking mode, which is enabled by default, accept() waits for a
- // connection request. In non blocking mode, you must call accept()
- // again if the error code BSD_EWOULDBLOCK is returned.
- #define MG_SOCK_INTR(fd) (fd == BSD_EWOULDBLOCK)
- #define socklen_t int
- #endif
- #ifndef MG_ENABLE_LOG
- #define MG_ENABLE_LOG 1
- #endif
- #ifndef MG_ENABLE_CUSTOM_CALLOC
- #define MG_ENABLE_CUSTOM_CALLOC 0
- #endif
- #ifndef MG_ENABLE_CUSTOM_LOG
- #define MG_ENABLE_CUSTOM_LOG 0 // Let user define their own MG_LOG
- #endif
- #ifndef MG_ENABLE_FREERTOS
- #define MG_ENABLE_FREERTOS 0 // FreeRTOS RTOS
- #endif
- #ifndef MG_ENABLE_TCPIP
- #define MG_ENABLE_TCPIP 0 // Mongoose built-in network stack
- #endif
- #ifndef MG_ENABLE_BSD_SOCKETS
- #define MG_ENABLE_BSD_SOCKETS 0 // BSD API support for built-in stack
- #endif
- #ifndef MG_ENABLE_BSD_PROTOTYPES
- #define MG_ENABLE_BSD_PROTOTYPES 1
- #endif
- #ifndef MG_ENABLE_LWIP
- #define MG_ENABLE_LWIP 0 // lwIP network stack
- #endif
- #ifndef MG_ENABLE_FREERTOS_TCP
- #define MG_ENABLE_FREERTOS_TCP 0 // Amazon FreeRTOS-TCP network stack
- #endif
- #ifndef MG_ENABLE_RL
- #define MG_ENABLE_RL 0 // ARM MDK network stack
- #endif
- #ifndef MG_ENABLE_SOCKET
- #define MG_ENABLE_SOCKET !MG_ENABLE_TCPIP
- #endif
- #ifndef MG_ENABLE_POLL
- #define MG_ENABLE_POLL 0
- #endif
- #ifndef MG_ENABLE_EPOLL
- #define MG_ENABLE_EPOLL 0
- #endif
- #ifndef MG_ENABLE_FATFS
- #define MG_ENABLE_FATFS 0
- #endif
- #ifndef MG_ENABLE_LFS
- #define MG_ENABLE_LFS 0
- #endif
- #ifndef MG_ENABLE_SSI
- #define MG_ENABLE_SSI 0
- #endif
- #ifndef MG_ENABLE_IPV6
- #define MG_ENABLE_IPV6 0
- #endif
- #ifndef MG_IPV6_V6ONLY
- #define MG_IPV6_V6ONLY 0 // IPv6 socket binds only to V6, not V4 address
- #endif
- #ifndef MG_ENABLE_MD5
- #define MG_ENABLE_MD5 1
- #endif
- // Set MG_ENABLE_WINSOCK=0 for Win32 builds with other external IP stack not
- // mentioned in arch_win32.h
- #ifndef MG_ENABLE_WINSOCK
- #define MG_ENABLE_WINSOCK 1
- #endif
- #ifndef MG_ENABLE_DIRLIST
- #define MG_ENABLE_DIRLIST 0
- #endif
- #ifndef MG_ENABLE_CUSTOM_RANDOM
- #define MG_ENABLE_CUSTOM_RANDOM 0
- #endif
- #ifndef MG_ENABLE_CUSTOM_MILLIS
- #define MG_ENABLE_CUSTOM_MILLIS 0
- #endif
- #ifndef MG_ENABLE_ASSERT
- #define MG_ENABLE_ASSERT 0
- #endif
- #ifndef MG_IO_SIZE
- #define MG_IO_SIZE 512 // Granularity of the send/recv IO buffer growth
- #endif
- #ifndef MG_MAX_RECV_SIZE
- #define MG_MAX_RECV_SIZE (3UL * 1024UL * 1024UL) // Maximum recv IO buffer size
- #endif
- #ifndef MG_DATA_SIZE
- #define MG_DATA_SIZE 32 // struct mg_connection :: data size
- #endif
- #ifndef MG_MAX_HTTP_HEADERS
- #define MG_MAX_HTTP_HEADERS 30
- #endif
- #ifndef MG_HTTP_INDEX
- #define MG_HTTP_INDEX "index.html"
- #endif
- #ifndef MG_PATH_MAX
- #ifdef PATH_MAX
- #define MG_PATH_MAX PATH_MAX
- #else
- #define MG_PATH_MAX 128
- #endif
- #endif
- #ifndef MG_SOCK_LISTEN_BACKLOG_SIZE
- #define MG_SOCK_LISTEN_BACKLOG_SIZE 128
- #endif
- #ifndef MG_DIRSEP
- #define MG_DIRSEP '/'
- #endif
- #ifndef MG_ENABLE_POSIX_FS
- #define MG_ENABLE_POSIX_FS 0
- #endif
- #ifndef MG_INVALID_SOCKET
- #define MG_INVALID_SOCKET (-1)
- #endif
- #ifndef MG_SOCKET_TYPE
- #define MG_SOCKET_TYPE int
- #endif
- #ifndef MG_SOCKET_ERRNO
- #define MG_SOCKET_ERRNO errno
- #endif
- #if MG_ENABLE_EPOLL
- #define MG_EPOLL_ADD(c) \
- do { \
- struct epoll_event ev = {EPOLLIN | EPOLLERR | EPOLLHUP, {c}}; \
- epoll_ctl(c->mgr->epoll_fd, EPOLL_CTL_ADD, (int) (size_t) c->fd, &ev); \
- } while (0)
- #define MG_EPOLL_MOD(c, wr) \
- do { \
- struct epoll_event ev = {EPOLLIN | EPOLLERR | EPOLLHUP, {c}}; \
- if (wr) ev.events |= EPOLLOUT; \
- epoll_ctl(c->mgr->epoll_fd, EPOLL_CTL_MOD, (int) (size_t) c->fd, &ev); \
- } while (0)
- #else
- #define MG_EPOLL_ADD(c)
- #define MG_EPOLL_MOD(c, wr)
- #endif
- #ifndef MG_ENABLE_PROFILE
- #define MG_ENABLE_PROFILE 0
- #endif
- #ifndef MG_ENABLE_TCPIP_DRIVER_INIT // mg_mgr_init() will also initialize
- #define MG_ENABLE_TCPIP_DRIVER_INIT 1 // enabled built-in driver for
- #endif // Mongoose built-in network stack
- #ifndef MG_TCPIP_IP // e.g. MG_IPV4(192, 168, 0, 223)
- #define MG_TCPIP_IP MG_IPV4(0, 0, 0, 0) // Default is 0.0.0.0 (DHCP)
- #endif
- #ifndef MG_TCPIP_MASK
- #define MG_TCPIP_MASK MG_IPV4(0, 0, 0, 0) // Default is 0.0.0.0 (DHCP)
- #endif
- #ifndef MG_TCPIP_GW
- #define MG_TCPIP_GW MG_IPV4(0, 0, 0, 0) // Default is 0.0.0.0 (DHCP)
- #endif
- #if MG_ENABLE_IPV6
- #ifndef MG_TCPIP_GLOBAL
- #define MG_TCPIP_GLOBAL MG_IPV6(0, 0, 0, 0, 0, 0, 0, 0)
- #endif
- #ifndef MG_TCPIP_IPV6_LINKLOCAL
- #define MG_TCPIP_IPV6_LINKLOCAL MG_IPV6(0, 0, 0, 0, 0, 0, 0, 0)
- #endif
- #ifndef MG_TCPIP_PREFIX_LEN
- #define MG_TCPIP_PREFIX_LEN 0
- #endif
- #ifndef MG_TCPIP_GW6
- #define MG_TCPIP_GW6 MG_IPV6(0, 0, 0, 0, 0, 0, 0, 0)
- #endif
- #endif
- #ifndef MG_SET_MAC_ADDRESS
- #define MG_SET_MAC_ADDRESS(mac)
- #endif
- #ifndef MG_TCPIP_DHCPNAME_SIZE
- #define MG_TCPIP_DHCPNAME_SIZE 18 // struct mg_tcpip_if :: dhcp_name size
- #endif
- #ifndef MG_SET_WIFI_CONFIG
- #define MG_SET_WIFI_CONFIG(ifp, driver_data)
- #endif
- #ifndef MG_ENABLE_TCPIP_PRINT_DEBUG_STATS
- #define MG_ENABLE_TCPIP_PRINT_DEBUG_STATS 0
- #endif
- #ifndef MG_ENABLE_CHACHA20
- #define MG_ENABLE_CHACHA20 1 // When set to 0, GCM is used. For MG_TLS_BUILTIN
- #endif
- // Macros to record timestamped events that happens with a connection.
- // They are saved into a c->prof IO buffer, each event is a name and a 32-bit
- // timestamp in milliseconds since connection init time.
- //
- // Test (run in two separate terminals):
- // make -C tutorials/http/http-server/ CFLAGS_EXTRA=-DMG_ENABLE_PROFILE=1
- // curl localhost:8000
- // Output:
- // 1ea1f1e7 2 net.c:150:mg_close_conn 3 profile:
- // 1ea1f1e8 2 net.c:150:mg_close_conn 1ea1f1e6 init
- // 1ea1f1e8 2 net.c:150:mg_close_conn 0 EV_OPEN
- // 1ea1f1e8 2 net.c:150:mg_close_conn 0 EV_ACCEPT
- // 1ea1f1e8 2 net.c:150:mg_close_conn 0 EV_READ
- // 1ea1f1e8 2 net.c:150:mg_close_conn 0 EV_HTTP_MSG
- // 1ea1f1e8 2 net.c:150:mg_close_conn 0 EV_WRITE
- // 1ea1f1e8 2 net.c:150:mg_close_conn 1 EV_CLOSE
- //
- // Usage:
- // Enable profiling by setting MG_ENABLE_PROFILE=1
- // Invoke MG_PROF_ADD(c, "MY_EVENT_1") in the places you'd like to measure
- #if MG_ENABLE_PROFILE
- struct mg_profitem {
- const char *name; // Event name
- uint32_t timestamp; // Milliseconds since connection creation (MG_EV_OPEN)
- };
- #define MG_PROFILE_ALLOC_GRANULARITY 256 // Can save 32 items wih to realloc
- // Adding a profile item to the c->prof. Must be as fast as possible.
- // Reallocation of the c->prof iobuf is not desirable here, that's why we
- // pre-allocate c->prof with MG_PROFILE_ALLOC_GRANULARITY.
- // This macro just inits and copies 8 bytes, and calls mg_millis(),
- // which should be fast enough.
- #define MG_PROF_ADD(c, name_) \
- do { \
- struct mg_iobuf *io = &c->prof; \
- uint32_t inittime = ((struct mg_profitem *) io->buf)->timestamp; \
- struct mg_profitem item = {name_, (uint32_t) mg_millis() - inittime}; \
- mg_iobuf_add(io, io->len, &item, sizeof(item)); \
- } while (0)
- // Initialising profile for a new connection. Not time sensitive
- #define MG_PROF_INIT(c) \
- do { \
- struct mg_profitem first = {"init", (uint32_t) mg_millis()}; \
- mg_iobuf_init(&(c)->prof, 0, MG_PROFILE_ALLOC_GRANULARITY); \
- mg_iobuf_add(&c->prof, c->prof.len, &first, sizeof(first)); \
- } while (0)
- #define MG_PROF_FREE(c) mg_iobuf_free(&(c)->prof)
- // Dumping the profile. Not time sensitive
- #define MG_PROF_DUMP(c) \
- do { \
- struct mg_iobuf *io = &c->prof; \
- struct mg_profitem *p = (struct mg_profitem *) io->buf; \
- struct mg_profitem *e = &p[io->len / sizeof(*p)]; \
- MG_INFO(("%lu profile:", c->id)); \
- while (p < e) { \
- MG_INFO(("%5lx %s", (unsigned long) p->timestamp, p->name)); \
- p++; \
- } \
- } while (0)
- #else
- #define MG_PROF_INIT(c)
- #define MG_PROF_FREE(c)
- #define MG_PROF_ADD(c, name)
- #define MG_PROF_DUMP(c)
- #endif
- // A non-owning view of an arbitrary byte buffer. Not NUL-terminated in general.
- // Use mg_str() or mg_str_n() to construct; use mg_strdup() for an owned copy.
- struct mg_str {
- char *buf; // Pointer to the data (not necessarily NUL-terminated)
- size_t len; // Number of bytes
- };
- // Using macro to avoid shadowing the C++ struct constructor, see #1298
- #define mg_str(s) mg_str_s(s)
- // Creates an mg_str from a NUL-terminated C string. Computes length via
- // strlen. Returns {NULL, 0} when s is NULL.
- struct mg_str mg_str(const char *s);
- // Creates an mg_str from a pointer and explicit byte count. s need not be
- // NUL-terminated. Does not copy the data.
- struct mg_str mg_str_n(const char *s, size_t n);
- // Case-insensitive strcmp for NUL-terminated C strings.
- // Returns 0 if equal, <0 if s1 < s2, >0 if s1 > s2.
- int mg_casecmp(const char *s1, const char *s2);
- // Compares two mg_str by content and length. Returns 0 if identical,
- // -1 if str1 < str2, 1 if str1 > str2. Length is used as a tiebreaker
- // when one string is a prefix of the other.
- int mg_strcmp(const struct mg_str str1, const struct mg_str str2);
- // Case-insensitive mg_strcmp.
- int mg_strcasecmp(const struct mg_str str1, const struct mg_str str2);
- // Returns a heap-allocated, NUL-terminated copy of s.
- // Returns {NULL, 0} on OOM or if s.buf is NULL or s.len is 0.
- // Caller must mg_free(result.buf) when done.
- struct mg_str mg_strdup(const struct mg_str s);
- // Matches a string against a glob pattern.
- //
- // Returns:
- // True if the whole str matches pattern.
- // Example:
- // if (mg_match(hm->uri, mg_str("/api/#"), NULL)) { ... }
- // Full examples:
- // tutorials/http/http-server, tutorials/http/link-checker,
- // tutorials/websocket/websocket-server
- // Related APIs:
- // mg_str(), mg_str_n(), mg_span(), mg_strcmp(), mg_strcasecmp()
- // Notes:
- // Pattern wildcards: ? matches one character, * matches any sequence except
- // '/', and # matches any sequence including '/'. If caps is not NULL, each
- // wildcard capture is stored as a zero-copy mg_str slice into str. Pass
- // caps=NULL when captures are not needed. The caps array size should be
- // at least the number of wildcards in a pattern plus one. The last cap
- // is initialised to an empty string.
- // Attention: the pattern must consume the whole str in order to match.
- bool mg_match(struct mg_str str, struct mg_str pattern, struct mg_str *caps);
- // Splits s at the first occurrence of sep. Sets *a to the part before sep
- // and *b to the part after it (sep is not included in either). Both slices
- // are zero-copy views into s. a or b may be NULL if that half is not needed.
- // If sep is not found, *a is the whole string and *b is empty.
- // Returns false if s is empty or s.buf is NULL.
- // Example - scan comma-separated key=value pairs:
- // ```c
- // struct mg_str entry, key, val;
- // struct mg_str s = mg_str("a=333,b=777,hello");
- //
- // while (mg_span(s, &entry, &s, ',')) {
- // mg_span(entry, &key, &val, '=');
- // printf("key: %.*s, val: %.*s\n", (int) key.len, key.buf, (int) val.len, val.buf);
- // }
- // ```
- bool mg_span(struct mg_str s, struct mg_str *a, struct mg_str *b, char sep);
- // Parses str as an unsigned integer into the val_len-byte value at *val.
- // val_len must be 1, 2, 4, or 8 (for uint8_t, uint16_t, uint32_t, uint64_t).
- // base must be 2, 10, or 16; pass 0 to auto-detect from a "0b" or "0x" prefix.
- // The entire string must consist of valid digits with no trailing characters.
- // Returns false on overflow, invalid input, unsupported base, or unsupported val_len.
- bool mg_str_to_num(struct mg_str str, int base, void *val, size_t val_len);
- // Lock-free, single-producer / single-consumer (SPSC) message queue.
- // Safe to write from an ISR and read from the main loop without locking,
- // as long as only one context writes and one context reads at a time.
- // Each message is stored with an internal 32-bit length prefix; the buf
- // pointers returned by mg_queue_book() and mg_queue_next() already skip it.
- //
- // Producer pattern:
- // char buf[1024];
- // if (mg_queue_book(&q, &buf, len) >= len) {
- // memcpy(buf, data, len);
- // mg_queue_add(&q, len);
- // }
- //
- // Consumer pattern:
- // char *buf;
- // size_t len = mg_queue_next(&q, &buf);
- // if (len > 0) { process(buf, len); mg_queue_del(&q, len); }
- struct mg_queue {
- char *buf; // Caller-supplied backing buffer
- size_t size; // Size of buf in bytes
- volatile size_t tail; // Read offset; updated by the consumer
- volatile size_t head; // Write offset; updated by the producer
- };
- // Initialises q to use the caller-supplied buf/size. buf must remain valid
- // for the lifetime of the queue.
- void mg_queue_init(struct mg_queue *q, char *buf, size_t size);
- // Reserves space for a message of len bytes. Sets *buf to the write location.
- // Returns the number of bytes available (>= len means the reservation
- // succeeded). Does NOT commit the message; call mg_queue_add() after writing.
- size_t mg_queue_book(struct mg_queue *q, char **buf, size_t len);
- // Commits the most recently reserved message of len bytes. Must be called
- // with the same len passed to the preceding mg_queue_book() call, after
- // the data has been written into the buffer it returned.
- void mg_queue_add(struct mg_queue *q, size_t len);
- // Returns the length of the oldest unconsumed message and sets *buf to its
- // start. Returns 0 if the queue is empty. Does NOT remove the message;
- // call mg_queue_del() after processing to advance the read position.
- size_t mg_queue_next(struct mg_queue *q, char **buf);
- // Removes the oldest message of len bytes. Must be called with the same len
- // returned by the preceding mg_queue_next() call.
- void mg_queue_del(struct mg_queue *q, size_t len);
- // Character output function. Called once per output character by mg_xprintf/mg_vxprintf.
- // arg is an arbitrary user pointer passed through from the caller.
- typedef void (*mg_pfn_t)(char, void *arg);
- // Custom %M/%m printer. Reads its own arguments from ap and writes via fn.
- // Returns the number of characters printed (excluding the quotes added by %m).
- typedef size_t (*mg_pm_t)(mg_pfn_t fn, void *arg, va_list *);
- // Formats fmt with printf-like specifiers, calling fn for each output character.
- // Returns the total number of characters printed. Supported specifiers:
- // - %c - expect char
- // - %f, %g - expect double
- // - %hhd, %hd, %d, %ld, %lld - for char, short, int, long, int64_t
- // - %hhu, %hu, %u, %lu, %llu - same but for unsigned variants
- // - %hhx, %hx, %x, %lx, %llx - same, unsigned and hex output
- // - %p - expects any pointer, prints 0x..... hex value
- // - %s - expects char *
- // - %% - prints the % character itself
- // - %X.Y - optional width and precision modifiers (e.g.: %1.2d)
- // - %.* - optional precision modifier, expected as int argument (e.g.: %.*d)
- // - %M - (EXTENSION) expects a pointer to a custom print function and its arguments
- // - %m - (EXTENSION) exactly like %M but double-quotes the output
- // - %M/%m (custom mg_pm_t printer; %m additionally wraps the output in quotes).
- //
- // There are higher level wrappers around these functions that use
- // predefined output functions, and can print to char buffer, or connection
- // send iobuffer, etc etc. - for example, mg_snrptinf(). The %M/%m non-standard
- // specifier allows to use custom formtter. There are several pre-defined
- // formatters:
- // - mg_print_base64 - prints a buffer as a base64-encoded string
- // - mg_print_esc - prints a JSON-escaped string
- // - mg_print_hex - prints a buffer as a hex string
- // - mg_print_ip - prints an IP address in a struct mg_str
- // - mg_print_ip_port - prints IP address and port in a struct mg_str
- // - mg_print_ip4 - prints an IPv4 address
- // - mg_print_ip6 - prints an IPv6 address
- // - mg_print_mac - prints a MAC address
- //
- // Usage example:
- //
- // ```c
- // struct a { int a, b; };
- //
- // size_t print_a(mg_pfn_t fn, void *arg, va_list *ap) {
- // struct a *p = va_arg(*ap, struct a *);
- // return mg_xprintf(fn, arg, "{%m:%d}", MG_ESC("a"), p->a);
- // }
- //
- // struct a temp = { 42, 43 };
- // char buf[100];
- //
- // mg_snprintf(buf, sizeof(buf), "%M", print_a, &temp); // {"a":42}
- // ```
- size_t mg_vxprintf(mg_pfn_t fn, void *arg, const char *fmt, va_list *);
- size_t mg_xprintf(mg_pfn_t fn, void *arg, const char *fmt, ...);
- // Formats data into a caller-supplied buffer.
- //
- // Returns:
- // Number of bytes that would be written if buf were large enough, like
- // snprintf().
- // Example:
- // char buf[20];
- // mg_snprintf(buf, sizeof(buf), "{%m:%d}", MG_ESC("status"), 1);
- // Full examples:
- // tutorials/http/link-checker, tutorials/http/redirect-to-https,
- // tutorials/mqtt/mqtt-dashboard/device
- // Related APIs:
- // mg_xprintf(), mg_printf(), mg_mprintf(), MG_ESC
- // Notes:
- // These functions are just wrappers around mg_xprintf().
- // Call with buf=NULL and len=0 to measure. NUL-terminates if the result fits
- // (return value < len). Supports mg_xprintf specifiers, including custom
- // %M/%m printers. Use MG_ESC when printing JSON strings.
- size_t mg_vsnprintf(char *buf, size_t len, const char *fmt, va_list *ap);
- size_t mg_snprintf(char *buf, size_t len, const char *fmt, ...);
- // Formats into a heap-allocated NUL-terminated string. Caller must mg_free() it.
- char *mg_vmprintf(const char *fmt, va_list *ap);
- char *mg_mprintf(const char *fmt, ...);
- // Formats into a mg_queue slot. Returns bytes written, or 0 if no space.
- size_t mg_queue_printf(struct mg_queue *, const char *fmt, ...);
- // Built-in %M/%m printer functions. Each reads its argument(s) from ap.
- size_t mg_print_base64(mg_pfn_t, void *arg, va_list *ap); // expects: const void *buf, size_t len
- size_t mg_print_esc(mg_pfn_t, void *arg, va_list *ap); // expects: int len, const char *str -- use MG_ESC()
- size_t mg_print_hex(mg_pfn_t, void *arg, va_list *ap); // expects: const void *buf, size_t len
- size_t mg_print_ip(mg_pfn_t, void *arg, va_list *ap); // expects: const struct mg_addr *
- size_t mg_print_ip_port(mg_pfn_t, void *arg, va_list *ap); // expects: const struct mg_addr *
- size_t mg_print_ip4(mg_pfn_t, void *arg, va_list *ap); // expects: uint32_t *ipv4
- size_t mg_print_ip6(mg_pfn_t, void *arg, va_list *ap); // expects: uint8_t[16] ipv6
- size_t mg_print_mac(mg_pfn_t, void *arg, va_list *ap); // expects: uint8_t[6] mac
- size_t mg_print_ieee64(mg_pfn_t, void *arg, va_list *ap); // expects: uint64_t
- size_t mg_print_l2addr(mg_pfn_t, void *arg, va_list *ap); // expects: uint8_t l2, uint8_t[n] n-byte l2-dependent address
- size_t mg_print_html_esc(mg_pfn_t, void *arg, va_list *ap); // expects: int len, const char *str -- use MG_ESC()
- // Output functions for use as the fn argument to mg_xprintf/mg_vxprintf.
- void mg_pfn_iobuf(char ch, void *param); // param: struct mg_iobuf * (resizes as needed)
- void mg_pfn_iobuf_noresize(char ch, void *param); // param: struct mg_iobuf * (fixed buffer, no resize)
- void mg_pfn_stdout(char c, void *param); // param: ignored, writes to stdout
- // Expands to the three arguments for %m to JSON-escape a string literal.
- // Example: mg_snprintf(buf, len, "%m", MG_ESC("hello")) -> "\"hello\""
- #define MG_ESC(str) mg_print_esc, 0, (str)
- // Logging
- //
- // Mongoose provides a set of functions and macros for logging. The application can
- // use these functions for its own purposes as well as the rest of Mongoose API.
- // Log levels
- enum { MG_LL_NONE, MG_LL_ERROR, MG_LL_INFO, MG_LL_DEBUG, MG_LL_VERBOSE };
- // Set Mongoose logging level. Example: `mg_log_set(MG_LL_INFO);`
- extern int mg_log_level; // Current log level, one of MG_LL_*
- #define mg_log_set(level_) mg_log_level = (level_)
- void mg_log(const char *fmt, ...);
- void mg_log_prefix(int ll, const char *file, int line, const char *fname);
- // Log a hex dump of binary data `buf`, `len`.
- void mg_hexdump(const void *buf, size_t len);
- // Set log printer function which prints one byte. Example:
- //
- // ```c
- // static void print_char(char ch, void *param) {
- // hal_uart_write_char(param, ch);
- // }
- // ...
- // mg_log_set_fn(print_char, USART3);
- // ```
- void mg_log_set_fn(mg_pfn_t fn, void *param);
- #if MG_ENABLE_LOG
- #if !defined(_MSC_VER) && \
- (!defined(__STDC_VERSION__) || __STDC_VERSION__ < 199901L)
- #define MG___FUNC__ ""
- #else
- #define MG___FUNC__ __func__ // introduced in C99
- #endif
- #define MG_LOG(level, args) \
- do { \
- if ((level) <= mg_log_level) { \
- mg_log_prefix((level), __FILE__, __LINE__, MG___FUNC__); \
- mg_log args; \
- } \
- } while (0)
- #else
- #define MG_LOG(level, args) \
- do { \
- if (0) mg_log args; \
- } while (0)
- #endif
- // Logging macros. Note: the argument is exactly like for mg_snprintf(),
- // and it should be enclosed in double parenthesis. Example:
- // ```c
- // MG_INFO(("Conn %lu, recv buf: %.*s", c->id, c->recv.len, c->recv.buf));
- // ```
- #define MG_ERROR(args) MG_LOG(MG_LL_ERROR, args)
- #define MG_INFO(args) MG_LOG(MG_LL_INFO, args)
- #define MG_DEBUG(args) MG_LOG(MG_LL_DEBUG, args)
- #define MG_VERBOSE(args) MG_LOG(MG_LL_VERBOSE, args)
- struct mg_timer {
- uint64_t period_ms; // Timer period in milliseconds
- uint64_t expire; // Expiration timestamp in milliseconds
- unsigned flags; // Possible flags values below
- #define MG_TIMER_ONCE 0 // Call function once
- #define MG_TIMER_REPEAT 1 // Call function periodically
- #define MG_TIMER_RUN_NOW 2 // Call immediately when timer is set
- #define MG_TIMER_CALLED 4 // Timer function was called at least once
- #define MG_TIMER_AUTODELETE 8 // mg_free() timer when done
- void (*fn)(void *); // Function to call
- void *arg; // Function argument
- struct mg_timer *next; // Linkage
- };
- void mg_timer_init(struct mg_timer **head, struct mg_timer *timer,
- uint64_t milliseconds, unsigned flags, void (*fn)(void *),
- void *arg);
- void mg_timer_free(struct mg_timer **head, struct mg_timer *);
- void mg_timer_poll(struct mg_timer **head, uint64_t new_ms);
- // Flags returned by mg_fs.st() and passed to mg_fs.open().
- enum { MG_FS_READ = 1, MG_FS_WRITE = 2, MG_FS_DIR = 4, MG_FS_EXCL = 8 };
- // Filesystem abstraction. Implement all function pointers to plug in a custom
- // filesystem. Short UNIX-style names are used deliberately to avoid conflicts
- // with libraries that define macros for stat(), read(), write(), etc.
- struct mg_fs {
- int (*st)(const char *path, size_t *size, time_t *mtime); // Stat: return MG_FS_* flags; size/mtime may be NULL
- void (*ls)(const char *path, void (*fn)(const char *, void *), void *); // List dir: call fn(name, arg) per entry
- void *(*op)(const char *path, int flags); // Open file; return opaque fd, or NULL on error
- void (*cl)(void *fd); // Close file
- size_t (*rd)(void *fd, void *buf, size_t len); // Read up to len bytes; return bytes read
- size_t (*wr)(void *fd, const void *buf, size_t len); // Write len bytes; return bytes written
- size_t (*sk)(void *fd, size_t offset); // Seek to offset from start; return new position
- bool (*mv)(const char *from, const char *to); // Rename/move file
- bool (*rm)(const char *path); // Delete file
- bool (*mkd)(const char *path); // Create directory
- };
- extern struct mg_fs mg_fs_posix; // POSIX filesystem (open/close/read/write/seek)
- extern struct mg_fs mg_fs_packed; // Read-only packed filesystem (see tutorials/core/embedded-filesystem)
- extern struct mg_fs mg_fs_fat; // FAT filesystem
- // Open file descriptor returned by mg_fs_open(). Bundles the raw fd with its fs.
- struct mg_fd {
- void *fd; // Opaque file handle from fs->op()
- struct mg_fs *fs; // Filesystem that owns fd
- };
- // Opens path with the given MG_FS_* flags. Returns NULL on error.
- struct mg_fd *mg_fs_open(struct mg_fs *fs, const char *path, int flags);
- // Closes fd and frees the mg_fd struct. Safe to call with NULL.
- void mg_fs_close(struct mg_fd *fd);
- // Sequential directory iterator. Call repeatedly with the same buf/len;
- // each call fills buf with the next entry name. Returns false when done.
- bool mg_fs_ls(struct mg_fs *fs, const char *path, char *buf, size_t len);
- // Reads the entire file into a heap-allocated buffer. The returned mg_str is
- // NUL-terminated. Caller must mg_free(result.buf). Returns {NULL,0} on error.
- struct mg_str mg_file_read(struct mg_fs *fs, const char *path);
- // Atomically writes buf/len to path (via a temp file + rename). Returns false on error.
- bool mg_file_write(struct mg_fs *fs, const char *path, const void *buf, size_t len);
- // Formats a string and atomically writes it to path. Returns false on error.
- bool mg_file_printf(struct mg_fs *fs, const char *path, const char *fmt, ...);
- // A file stored in memory (flash or RAM), used by mg_fs_packed.
- struct mg_mem_file {
- const char *path; // Virtual file path, e.g. "/web_root/index.html"
- const unsigned char *data; // Pointer to file content
- size_t size; // Content size in bytes
- time_t mtime; // Modification time (may be 0)
- };
- // Pointer to a NULL-path-terminated array of in-memory files for mg_fs_packed.
- // Override to serve a custom set of files:
- // static const struct mg_mem_file my_files[] = {
- // {"/index.html", data, sizeof(data), 0},
- // {NULL, NULL, 0, 0},
- // };
- // mg_mem_files = my_files;
- extern const struct mg_mem_file *mg_mem_files;
- // Looks up path in the packed file array. Returns an mg_str pointing directly
- // into the stored data (zero-copy). Returns {NULL,0} if not found.
- struct mg_str mg_unpacked(const char *path);
- // Array of packed files generated by the "pack" utility into packed_fs.c.
- // Activate by assigning: mg_mem_files = mg_packed_files;
- extern const struct mg_mem_file mg_packed_files[];
- #if MG_ENABLE_ASSERT
- #include <assert.h>
- #elif !defined(assert)
- #define assert(x)
- #endif
- // Wrappers around calloc/free. Override by defining MG_ENABLE_CUSTOM_CALLOC=1
- // and providing your own implementations.
- void *mg_calloc(size_t count, size_t size);
- void mg_free(void *ptr);
- // Zeroes len bytes at buf using a volatile write loop that the compiler cannot
- // elide. Safe to call with buf=NULL. Use instead of memset() for clearing
- // sensitive data (keys, passwords).
- void mg_bzero(volatile unsigned char *buf, size_t len);
- // Fixed-length constant-time byte equality. Use for MACs, tags, signatures.
- bool mg_memeq(const void *a, const void *b, size_t n);
- // Fills buf with len cryptographically random bytes. Uses the best available
- // hardware or OS source (hardware RNG, /dev/urandom, CryptGenRandom, etc.).
- // Falls back to rand() with an error log if no strong source is available.
- // Returns true when a strong source was used, false on fallback to rand().
- // Override by defining MG_ENABLE_CUSTOM_RANDOM=1 and providing your own impl.
- bool mg_random(void *buf, size_t len);
- // Fills buf with len-1 random alphanumeric characters ([a-zA-Z0-9]) and
- // NUL-terminates. Returns buf.
- char *mg_random_str(char *buf, size_t len);
- // Computes CRC32 (polynomial 0xEDB88320) over buf/len. Pass crc=0 to start
- // a new checksum; pass the result of a prior call to extend over more data.
- uint32_t mg_crc32(uint32_t crc, const char *buf, size_t len);
- // Computes CRC16 (HDLC, polynomial 0x8408) over buf/len. Pass crc=0 to start
- // a new checksum; pass the result of a prior call to extend over more data.
- uint16_t mg_crc16(uint16_t crc, const char *buf, size_t len);
- // Returns true if path is safe to serve from the filesystem. Rejects paths
- // that start with '~' or '..', or contain a '/../' component, to prevent
- // directory traversal attacks.
- bool mg_path_is_sane(const struct mg_str path);
- // Busy-waits for at least ms milliseconds using mg_millis(). Blocks the
- // calling context; avoid in event handlers.
- void mg_delayms(unsigned int ms);
- uint64_t mg_timegm(unsigned int year, unsigned int month, unsigned int day,
- unsigned int hour, unsigned int min, unsigned int sec);
- // Packs four byte values into a uint32_t in big-endian order.
- // MG_U32(1, 2, 3, 4) == 0x01020304
- #define MG_U32(a, b, c, d) \
- (((uint32_t) ((a) &255) << 24) | ((uint32_t) ((b) &255) << 16) | \
- ((uint32_t) ((c) &255) << 8) | (uint32_t) ((d) &255))
- // Constructs an IPv4 address in network byte order from four decimal octets.
- // Usage: uint32_t ip = MG_IPV4(192, 168, 1, 1);
- #define MG_IPV4(a, b, c, d) mg_htonl(MG_U32(a, b, c, d))
- // Expands to a brace-enclosed byte initialiser for a 16-byte IPv6 address.
- // Arguments are the eight 16-bit groups in the address, e.g.:
- // uint8_t ip6[16] = MG_IPV6(0x2001, 0xdb8, 0, 0, 0, 0, 0, 1);
- #define MG_IPV6(a, b, c, d, e, f, g ,h) \
- { (uint8_t)((a)>>8),(uint8_t)(a), \
- (uint8_t)((b)>>8),(uint8_t)(b), \
- (uint8_t)((c)>>8),(uint8_t)(c), \
- (uint8_t)((d)>>8),(uint8_t)(d), \
- (uint8_t)((e)>>8),(uint8_t)(e), \
- (uint8_t)((f)>>8),(uint8_t)(f), \
- (uint8_t)((g)>>8),(uint8_t)(g), \
- (uint8_t)((h)>>8),(uint8_t)(h) }
- // For printing IPv4 addresses: printf("%d.%d.%d.%d\n", MG_IPADDR_PARTS(&ip))
- #define MG_U8P(ADDR) ((uint8_t *) (ADDR))
- #define MG_IPADDR_PARTS(ADDR) \
- MG_U8P(ADDR)[0], MG_U8P(ADDR)[1], MG_U8P(ADDR)[2], MG_U8P(ADDR)[3]
- // Read an unaligned big-endian value from byte pointer p into a native integer.
- // Safe on architectures that forbid unaligned access (e.g. Cortex-M0).
- #define MG_LOAD_BE16(p) \
- ((uint16_t) (((uint16_t) MG_U8P(p)[0] << 8U) | MG_U8P(p)[1]))
- #define MG_LOAD_BE24(p) \
- ((uint32_t) (((uint32_t) MG_U8P(p)[0] << 16U) | \
- ((uint32_t) MG_U8P(p)[1] << 8U) | MG_U8P(p)[2]))
- #define MG_LOAD_BE32(p) \
- ((uint32_t) (((uint32_t) MG_U8P(p)[0] << 24U) | \
- ((uint32_t) MG_U8P(p)[1] << 16U) | \
- ((uint32_t) MG_U8P(p)[2] << 8U) | MG_U8P(p)[3]))
- #define MG_LOAD_BE64(p) \
- ((uint64_t) (((uint64_t) MG_U8P(p)[0] << 56U) | \
- ((uint64_t) MG_U8P(p)[1] << 48U) | \
- ((uint64_t) MG_U8P(p)[2] << 40U) | \
- ((uint64_t) MG_U8P(p)[3] << 32U) | \
- ((uint64_t) MG_U8P(p)[4] << 24U) | \
- ((uint64_t) MG_U8P(p)[5] << 16U) | \
- ((uint64_t) MG_U8P(p)[6] << 8U) | MG_U8P(p)[7]))
- // Write a native integer to byte pointer p in big-endian byte order.
- // Safe on architectures that forbid unaligned access.
- #define MG_STORE_BE16(p, n) \
- do { \
- MG_U8P(p)[0] = (uint8_t) ((n) >> 8U); \
- MG_U8P(p)[1] = (uint8_t) (n); \
- } while (0)
- #define MG_STORE_BE24(p, n) \
- do { \
- MG_U8P(p)[0] = (uint8_t) ((n) >> 16U); \
- MG_U8P(p)[1] = (uint8_t) ((n) >> 8U); \
- MG_U8P(p)[2] = (uint8_t) (n); \
- } while (0)
- #define MG_STORE_BE32(p, n) \
- do { \
- MG_U8P(p)[0] = (uint8_t) ((n) >> 24U); \
- MG_U8P(p)[1] = (uint8_t) ((n) >> 16U); \
- MG_U8P(p)[2] = (uint8_t) ((n) >> 8U); \
- MG_U8P(p)[3] = (uint8_t) (n); \
- } while (0)
- #define MG_STORE_BE64(p, n) \
- do { \
- MG_U8P(p)[0] = (uint8_t) ((n) >> 56U); \
- MG_U8P(p)[1] = (uint8_t) ((n) >> 48U); \
- MG_U8P(p)[2] = (uint8_t) ((n) >> 40U); \
- MG_U8P(p)[3] = (uint8_t) ((n) >> 32U); \
- MG_U8P(p)[4] = (uint8_t) ((n) >> 24U); \
- MG_U8P(p)[5] = (uint8_t) ((n) >> 16U); \
- MG_U8P(p)[6] = (uint8_t) ((n) >> 8U); \
- MG_U8P(p)[7] = (uint8_t) (n); \
- } while (0)
- // Network / host byte-order conversion (big-endian <-> native).
- // mg_htons/mg_htonl/mg_htonll are aliases for the same operation (symmetric).
- uint16_t mg_ntohs(uint16_t net);
- uint32_t mg_ntohl(uint32_t net);
- uint64_t mg_ntohll(uint64_t net);
- #define mg_htons(x) mg_ntohs(x)
- #define mg_htonl(x) mg_ntohl(x)
- #define mg_htonll(x) mg_ntohll(x)
- // Memory-mapped register access: reads/writes a volatile uint32_t at address x.
- #define MG_REG(x) ((volatile uint32_t *) (x))[0]
- // Produces a uint32_t with bit x set. x must be 0-31.
- #define MG_BIT(x) (((uint32_t) 1U) << (x))
- // Clears bits in CLRMASK and sets bits in SETMASK in register R atomically
- // (read-modify-write). Example: MG_SET_BITS(MG_REG(addr), 0xF, 0x3);
- #define MG_SET_BITS(R, CLRMASK, SETMASK) (R) = ((R) & ~(CLRMASK)) | (SETMASK)
- // Round x up / down to the nearest multiple of a. Returns x when a is 0.
- #define MG_ROUND_UP(x, a) ((a) == 0 ? (x) : ((((x) + (a) -1) / (a)) * (a)))
- #define MG_ROUND_DOWN(x, a) ((a) == 0 ? (x) : (((x) / (a)) * (a)))
- #if defined(__GNUC__) && defined(__arm__)
- #ifdef __ZEPHYR__
- #define MG_ARM_DISABLE_IRQ() __asm__ __volatile__("cpsid i" : : : "memory")
- #define MG_ARM_ENABLE_IRQ() __asm__ __volatile__("cpsie i" : : : "memory")
- #else
- #define MG_ARM_DISABLE_IRQ() asm volatile("cpsid i" : : : "memory")
- #define MG_ARM_ENABLE_IRQ() asm volatile("cpsie i" : : : "memory")
- #endif // !ZEPHYR
- #elif defined(__CCRH__)
- #define MG_RH850_DISABLE_IRQ() __DI()
- #define MG_RH850_ENABLE_IRQ() __EI()
- #else
- #define MG_ARM_DISABLE_IRQ()
- #define MG_ARM_ENABLE_IRQ()
- #endif
- #if defined(__CC_ARM)
- #define MG_DSB() __dsb(0xf)
- #elif defined(__ARMCC_VERSION)
- #define MG_DSB() __builtin_arm_dsb(0xf)
- #elif defined(__GNUC__) && defined(__arm__) && defined(__thumb__)
- #ifdef __ZEPHYR__
- #define MG_DSB() __asm__("DSB 0xf")
- #else
- #define MG_DSB() asm("DSB 0xf")
- #endif // !ZEPHYR
- #elif defined(__ICCARM__)
- #define MG_DSB() __iar_builtin_DSB()
- #else
- #define MG_DSB()
- #endif
- struct mg_addr;
- int mg_check_ip_acl(struct mg_str acl, struct mg_addr *remote_ip);
- // Linked list management macros
- #define LIST_ADD_HEAD(type_, head_, elem_) \
- do { \
- (elem_)->next = (*head_); \
- *(head_) = (elem_); \
- } while (0)
- #define LIST_ADD_TAIL(type_, head_, elem_) \
- do { \
- type_ **h = head_; \
- while (*h != NULL) h = &(*h)->next; \
- *h = (elem_); \
- } while (0)
- #define LIST_DELETE(type_, head_, elem_) \
- do { \
- type_ **h = head_; \
- while (*h != (elem_)) h = &(*h)->next; \
- *h = (elem_)->next; \
- } while (0)
- // Returns the port from url. Uses scheme defaults when no port is explicit:
- // http/ws=80, https/wss=443, mqtt=1883, mqtts=8883. Returns 0 if unknown.
- unsigned short mg_url_port(const char *url);
- // Returns true if url uses a TLS scheme (https, wss, mqtts, ssl, tls, tcps).
- bool mg_url_is_ssl(const char *url);
- // Returns the hostname from url as mg_str, without port or brackets.
- // E.g. "http://foo.com:8080/x" -> "foo.com". Not NUL-terminated.
- struct mg_str mg_url_host(const char *url);
- // Returns the username from url (user:pass@host form) as mg_str.
- // Returns an empty mg_str if no credentials are present. Not NUL-terminated.
- struct mg_str mg_url_user(const char *url);
- // Returns the password from url (user:pass@host form) as mg_str.
- // Returns an empty mg_str if no credentials are present. Not NUL-terminated.
- struct mg_str mg_url_pass(const char *url);
- // Returns a pointer to the URI path in url (e.g. "/api/v1").
- // Returns "/" if the url has no path. Points into the original url string.
- const char *mg_url_uri(const char *url);
- // Dynamically-sized I/O buffer. len <= size always holds.
- struct mg_iobuf {
- unsigned char *buf; // Heap-allocated data buffer
- size_t size; // Allocated capacity (rounded up to align)
- size_t len; // Number of bytes currently stored
- size_t align; // Allocation granularity; capacity is always a multiple of this
- };
- // Initializes io to empty, then allocates size bytes with the given alignment.
- // Returns false on allocation failure.
- bool mg_iobuf_init(struct mg_iobuf *io, size_t size, size_t align);
- // Resizes the buffer to new_size (rounded up to io->align). new_size=0 frees
- // the buffer. Uses mg_calloc+mg_free (not realloc) so old memory is zeroed on release.
- // Returns false on allocation failure.
- bool mg_iobuf_resize(struct mg_iobuf *io, size_t new_size);
- // Frees the buffer and zeroes the struct. Equivalent to mg_iobuf_resize(io, 0).
- void mg_iobuf_free(struct mg_iobuf *io);
- // Inserts len bytes from buf at offset ofs, shifting existing data right.
- // Pass buf=NULL to reserve space without writing. Returns bytes inserted, 0 on OOM.
- size_t mg_iobuf_add(struct mg_iobuf *io, size_t ofs, const void *buf, size_t len);
- // Removes len bytes at ofs, shifting remaining data left. Clamps to available data.
- // Returns bytes actually removed.
- size_t mg_iobuf_del(struct mg_iobuf *io, size_t ofs, size_t len);
- size_t mg_base64_update(unsigned char input_byte, char *buf, size_t len);
- size_t mg_base64_final(char *buf, size_t len);
- size_t mg_base64_encode(const unsigned char *p, size_t n, char *buf, size_t);
- size_t mg_base64_decode(const char *src, size_t n, char *dst, size_t);
- size_t mg_base64url_encode(const unsigned char *p, size_t n, char *buf,
- size_t);
- size_t mg_base64url_decode(const char *src, size_t n, char *dst, size_t);
- typedef struct {
- uint32_t buf[4];
- uint32_t bits[2];
- unsigned char in[64];
- } mg_md5_ctx;
- void mg_md5_init(mg_md5_ctx *c);
- void mg_md5_update(mg_md5_ctx *c, const unsigned char *data, size_t len);
- void mg_md5_final(mg_md5_ctx *c, unsigned char[16]);
- typedef struct {
- uint32_t state[5];
- uint32_t count[2];
- unsigned char buffer[64];
- } mg_sha1_ctx;
- void mg_sha1_init(mg_sha1_ctx *);
- void mg_sha1_update(mg_sha1_ctx *, const unsigned char *data, size_t len);
- void mg_sha1_final(unsigned char digest[20], mg_sha1_ctx *);
- // https://github.com/B-Con/crypto-algorithms
- // Author: Brad Conte (brad AT bradconte.com)
- // Disclaimer: This code is presented "as is" without any guarantees.
- // Details: Defines the API for the corresponding SHA1 implementation.
- // Copyright: public domain
- typedef struct {
- uint32_t state[8];
- uint64_t bits;
- uint32_t len;
- unsigned char buffer[64];
- } mg_sha256_ctx;
- void mg_sha256_init(mg_sha256_ctx *);
- void mg_sha256_update(mg_sha256_ctx *, const unsigned char *data, size_t len);
- void mg_sha256_final(unsigned char digest[32], mg_sha256_ctx *);
- void mg_sha256(uint8_t dst[32], uint8_t *data, size_t datasz);
- void mg_hmac_sha256(uint8_t dst[32], uint8_t *key, size_t keysz, uint8_t *data,
- size_t datasz);
- typedef struct {
- uint64_t state[8];
- uint8_t buffer[128];
- uint64_t bitlen[2];
- uint32_t datalen;
- } mg_sha384_ctx;
- void mg_sha384_init(mg_sha384_ctx *ctx);
- void mg_sha384_update(mg_sha384_ctx *ctx, const uint8_t *data, size_t len);
- void mg_sha384_final(uint8_t digest[48], mg_sha384_ctx *ctx);
- void mg_sha384(uint8_t dst[48], uint8_t *data, size_t datasz);
- struct mg_connection;
- // User-supplied event handler. ev is enum mg_event; ev_data type depends on
- // the event (see enum below). c->fn_data is the user pointer passed to
- // mg_listen(), mg_connect(), mg_*_listen(), mg_*_connect().
- typedef void (*mg_event_handler_t)(struct mg_connection *, int ev,
- void *ev_data);
- // Fires ev on connection c, invoking c->fn and c->pfn with ev_data.
- void mg_call(struct mg_connection *c, int ev, void *ev_data);
- // Sets c->is_closing and fires MG_EV_ERROR with a printf-formatted message.
- void mg_error(struct mg_connection *c, const char *fmt, ...);
- // Event codes passed to mg_event_handler_t. Each entry shows the type of
- // ev_data cast to use inside the handler, e.g.: char *msg = (char *) ev_data;
- enum mg_event {
- // Event Meaning ev_data type
- MG_EV_ERROR, // Error char *error_message
- MG_EV_OPEN, // Connection created NULL
- MG_EV_POLL, // mg_mgr_poll iteration uint64_t *uptime_millis
- MG_EV_RESOLVE, // Host name is resolved NULL
- MG_EV_CONNECT, // Connection established NULL
- MG_EV_ACCEPT, // Connection accepted NULL
- MG_EV_TLS_HS, // TLS handshake succeeded NULL
- MG_EV_READ, // Data received from socket long *bytes_read
- MG_EV_WRITE, // Data written to socket long *bytes_written
- MG_EV_CLOSE, // Connection closed NULL
- MG_EV_HTTP_HDRS, // HTTP headers struct mg_http_message *
- MG_EV_HTTP_MSG, // Full HTTP request/response struct mg_http_message *
- MG_EV_WS_OPEN, // Websocket handshake done struct mg_http_message *
- MG_EV_WS_MSG, // Websocket msg, text or bin struct mg_ws_message *
- MG_EV_WS_CTL, // Websocket control msg struct mg_ws_message *
- MG_EV_MQTT_CMD, // MQTT low-level command struct mg_mqtt_message *
- MG_EV_MQTT_MSG, // MQTT PUBLISH received struct mg_mqtt_message *
- MG_EV_MQTT_OPEN, // MQTT CONNACK received int *connack_status_code
- MG_EV_SNTP_TIME, // SNTP time received uint64_t *epoch_millis
- MG_EV_WAKEUP, // mg_wakeup() data received struct mg_str *data
- MG_EV_MDNS_REQ, // mDNS request struct mg_mdns_req *
- MG_EV_MDNS_RESP, // mDNS response struct mg_mdns_resp *
- MG_EV_MODBUS_REQ, // Modbus TCP request struct mg_modbus_req *
- MG_EV_USER // Starting ID for user events
- };
- // DNS server configuration used by struct mg_mgr.
- struct mg_dns {
- const char *url; // DNS server URL, e.g. "udp://8.8.8.8:53"
- struct mg_connection *c; // Active DNS connection; NULL when idle
- };
- // Network address: IPv4 or IPv6 address plus port. All values in network byte order.
- struct mg_addr {
- union { // IP address bytes in network byte order
- uint8_t ip[16]; // Raw 16-byte buffer; IPv4 uses the first 4 bytes
- uint32_t ip4; // IPv4 address alias (same storage as ip[0..3])
- uint64_t ip6[2]; // IPv6 address as two 64-bit words
- } addr;
- uint16_t port; // TCP or UDP port in network byte order
- uint8_t scope_id; // IPv6 scope ID (from the %N suffix in the address)
- bool is_ip6; // True when this address holds an IPv6 address
- };
- union mg_pipe {
- MG_SOCKET_TYPE fd;
- void *q;
- };
- // Central event manager. Zero-initialise with mg_mgr_init() before use.
- struct mg_mgr {
- struct mg_connection *conns; // Linked list of all open connections
- struct mg_dns dns4; // IPv4 DNS server (default: 8.8.8.8:53)
- struct mg_dns dns6; // IPv6 DNS server (default: [2001:4860:4860::8888]:53)
- struct mg_connection *mdns; // mDNS listener connection, or NULL
- int dnstimeout; // DNS resolve timeout in ms (default: 3000)
- bool use_dns6; // If true, prefer DNS6 for hostname resolution
- unsigned long nextid; // Auto-incrementing counter for connection IDs
- void *userdata; // Arbitrary user pointer
- void *tls_ctx; // Shared TLS context for all TLS connections
- uint16_t mqtt_id; // Packet ID counter for MQTT pub/sub
- void *active_dns_requests; // Pending DNS queries (internal)
- void *active_mdns_requests; // Pending mDNS resolver queries (internal)
- struct mg_timer *timers; // Linked list of active timers
- int epoll_fd; // epoll file descriptor; -1 when unused (MG_EPOLL_ENABLE=1)
- struct mg_tcpip_if *ifp; // Builtin TCP/IP stack: network interface pointer
- size_t extraconnsize; // Builtin TCP/IP stack: extra bytes allocated per connection
- union mg_pipe pipe; // Socketpair write-end / queue, used by mg_wakeup()
- #if MG_ENABLE_FREERTOS_TCP
- SocketSet_t ss; // FreeRTOS-TCP socket set
- #endif
- };
- // A single network connection. Do not allocate directly; use mg_connect() or
- // mg_listen(). Each connection has an event handler fn called for every event.
- struct mg_connection {
- struct mg_connection *next; // Next connection in mgr->conns linked list
- struct mg_mgr *mgr; // Manager that owns this connection
- struct mg_addr loc; // Local address (IP + port)
- struct mg_addr rem; // Remote address (IP + port)
- void *fd; // OS socket handle or LWIP PCB pointer
- unsigned long id; // Unique, auto-incrementing connection ID
- struct mg_iobuf recv; // Received data; consume in MG_EV_READ handler
- struct mg_iobuf send; // Data to send; append with mg_send() / mg_printf()
- struct mg_iobuf prof; // Profiling data (MG_ENABLE_PROFILE only)
- struct mg_iobuf rtls; // TLS only: encrypted data buffered before decryption
- mg_event_handler_t fn; // User event handler
- void *fn_data; // User-supplied argument passed to fn
- mg_event_handler_t pfn; // Protocol-level handler (set by protocol modules)
- void *pfn_data; // Protocol-level handler argument
- char data[MG_DATA_SIZE]; // Scratch space for protocol state; freely readable
- void *tls; // TLS state (internal)
- unsigned dscp : 6; // Differentiated Services Code Point
- #define MG_DSCP_CS(class_) ((class_) << 3)
- #define MG_DSCP_AF(class_, drop_) (((class_) << 3) | ((drop_) << 1))
- #define MG_DSCP_EF 46
- unsigned is_listening : 1; // Listening connection; accepts inbound connections
- unsigned is_client : 1; // Outbound connection created by mg_connect()
- unsigned is_accepted : 1; // Inbound connection accepted from a listener
- unsigned is_resolving : 1; // DNS resolution is in progress
- unsigned is_arplooking : 1; // ARP resolution is in progress (builtin TCP/IP)
- unsigned is_connecting : 1; // Non-blocking TCP connect is in progress
- unsigned is_tls : 1; // TLS connection
- unsigned is_tls_hs : 1; // TLS handshake is in progress
- unsigned is_udp : 1; // UDP connection (not TCP)
- unsigned is_websocket : 1; // WebSocket connection
- unsigned is_mqtt5 : 1; // MQTT5 connection (set by mg_mqtt_login)
- unsigned is_hexdumping : 1; // Log hex dump of all in/out traffic
- unsigned is_draining : 1; // Flush send buffer, then close
- unsigned is_closing : 1; // Close and free immediately on next poll
- unsigned is_full : 1; // Pause incoming reads until cleared
- unsigned is_tls_throttled : 1; // TLS write was throttled; retry pending
- unsigned is_resp : 1; // HTTP: response is still being generated
- unsigned is_readable : 1; // Socket is ready to read (epoll/select)
- unsigned is_writable : 1; // Socket is ready to write (epoll/select)
- };
- // Runs one iteration of the event loop.
- //
- // Example:
- // while (keep_running) mg_mgr_poll(&mgr, 50);
- // Full examples:
- // tutorials/http/http-server, tutorials/mqtt/mqtt-client,
- // tutorials/websocket/websocket-server, tutorials/core/timers
- // Related APIs:
- // mg_mgr_init(), mg_mgr_free(), mg_timer_add(), mg_wakeup()
- // Notes:
- // Waits up to ms milliseconds for I/O events; use ms=0 to return
- // immediately. Calls event handlers for ready connections and fires expired
- // timers. Call repeatedly from the main loop or a dedicated network task.
- void mg_mgr_poll(struct mg_mgr *, int ms);
- // Initialises an event manager before use.
- //
- // Example:
- // struct mg_mgr mgr;
- // mg_mgr_init(&mgr);
- // Full examples:
- // tutorials/http/http-server, tutorials/mqtt/mqtt-client,
- // tutorials/websocket/websocket-server, tutorials/core/embedded-filesystem
- // Related APIs:
- // mg_mgr_poll(), mg_mgr_free(), mg_http_listen(), mg_connect()
- // Notes:
- // Sets safe defaults such as DNS servers, DNS timeout, epoll/SIGPIPE setup,
- // and TLS context. Call before creating connections, listeners, or timers.
- // Set mgr.userdata after this call if your application needs it.
- // On embedded systems, if the built-in TCP/IP stack is enabled
- // (MG_ENABLE_TCPIP=1) and one built-in driver is selected, e.g.
- // MG_ENABLE_DRIVER_STM32H=1, mg_mgr_init() also calls mg_tcpip_init().
- // If no driver is selected, automatic driver init is disabled, or multiple
- // interfaces are intended, call mg_tcpip_init() separately.
- void mg_mgr_init(struct mg_mgr *);
- // Closes all connections, frees all timers, and releases the TLS context.
- // Safe to call on a partially initialised mgr.
- void mg_mgr_free(struct mg_mgr *);
- // Creates a listening connection on url (e.g. "tcp://0.0.0.0:8080").
- // Fires MG_EV_OPEN on the listener, then MG_EV_ACCEPT for each new client.
- // Returns NULL on error.
- struct mg_connection *mg_listen(struct mg_mgr *, const char *url,
- mg_event_handler_t fn, void *fn_data);
- // Opens an outbound connection to url (e.g. "tcp://example.com:80").
- // DNS resolution is asynchronous. Fires MG_EV_RESOLVE, then MG_EV_CONNECT
- // when the connection is established (or MG_EV_ERROR on failure).
- // Returns NULL on error (OOM, network down, null url).
- struct mg_connection *mg_connect(struct mg_mgr *, const char *url,
- mg_event_handler_t fn, void *fn_data);
- // Wraps an existing OS file descriptor in a Mongoose connection.
- // The connection is added to mgr and fires MG_EV_OPEN immediately.
- // Useful for integrating pre-opened sockets (e.g. stdin, accept() fd).
- struct mg_connection *mg_wrapfd(struct mg_mgr *mgr, int fd,
- mg_event_handler_t fn, void *fn_data);
- // Sets the 6-bit Differentiated Services Code Point for outgoing datagrams.
- // Call on MG_EV_OPEN for UDP listeners, MG_EV_CONNECT for clients, or
- // MG_EV_ACCEPT for TCP servers, before sending application data.
- bool mg_dscp(struct mg_connection *, uint8_t dscp);
- // Called internally after DNS resolution completes to create the OS socket
- // and initiate the TCP/IP connect. Normally not called by user code.
- void mg_connect_resolved(struct mg_connection *);
- // Appends buf/len to c->send. Returns true on success, false on OOM
- // (which also fires MG_EV_ERROR and schedules the connection for close).
- // Data is sent asynchronously by the next mg_mgr_poll() call.
- bool mg_send(struct mg_connection *, const void *, size_t);
- // Formats data and appends it to a connection send buffer.
- //
- // Returns:
- // Number of bytes appended, or 0 on OOM.
- // Example:
- // mg_printf(c, "GET / HTTP/1.0\r\nHost: %.*s\r\n\r\n",
- // (int) host.len, host.buf);
- // Full examples:
- // tutorials/http/http-client, tutorials/http/http-proxy-client,
- // tutorials/http/http-restful-server
- // Related APIs:
- // mg_send(), mg_snprintf(), mg_http_reply(), mg_ws_printf()
- // Notes:
- // Data is sent asynchronously by a later mg_mgr_poll() call. Supports
- // mg_xprintf specifiers, including custom %M/%m printers. See src/fmt.h for
- // the full specifier list.
- size_t mg_printf(struct mg_connection *, const char *fmt, ...);
- size_t mg_vprintf(struct mg_connection *, const char *fmt, va_list *ap);
- // Parses an IP address string str into addr. Handles "localhost", plain IPv4
- // (e.g. "1.2.3.4"), IPv6 with optional brackets and scope ID, and
- // IPv4-mapped IPv6 (::ffff:1.2.3.4). Does NOT parse the port.
- // Returns true on success; addr->is_ip6 and addr->addr are set.
- bool mg_aton(struct mg_str str, struct mg_addr *addr);
- // Low-level functions for integrating with custom network stacks.
- // Allocates a new connection struct with mgr->extraconnsize extra bytes.
- // Returns NULL on OOM.
- struct mg_connection *mg_alloc_conn(struct mg_mgr *);
- // Fires MG_EV_CLOSE, frees all buffers (recv/send/rtls), removes c from
- // mgr->conns, and calls mg_free(c). Do not use c after this call.
- void mg_close_conn(struct mg_connection *c);
- // Creates and binds the OS socket for a listening connection c at url.
- // Called internally by mg_listen(); expose for custom network stack use.
- // Returns false on error.
- bool mg_open_listener(struct mg_connection *c, const char *url);
- // Thread-safe wakeup: fires MG_EV_WAKEUP on the connection whose id matches,
- // with ev_data pointing to an mg_str containing buf/len.
- // Requires mg_wakeup_init() to have been called first.
- // Returns false if the pipe is not initialised or conn_id is 0.
- // Safe to call from any thread or interrupt context.
- bool mg_wakeup(struct mg_mgr *, unsigned long id, const void *buf, size_t len);
- // Initialises the internal socketpair used by mg_wakeup(). Call once after
- // mg_mgr_init() if you intend to wake the event loop from another thread.
- // Returns false on failure (e.g. socketpair creation failed).
- bool mg_wakeup_init(struct mg_mgr *);
- // Deprecated API, do not expose. Use mg_timer_expired instead
- struct mg_timer *mg_timer_add(struct mg_mgr *mgr, uint64_t milliseconds,
- unsigned flags, void (*fn)(void *), void *arg);
- // Like mg_connect() but also sets a protocol-level handler pfn/pfn_data.
- // Used internally by protocol modules (MQTT, WebSocket, etc.).
- struct mg_connection *mg_connect_svc(struct mg_mgr *mgr, const char *url,
- mg_event_handler_t fn, void *fn_data,
- mg_event_handler_t pfn, void *pfn_data);
- // Restores c->rem from a saved address buffer written by the caller, then
- // maps the IP back through the builtin TCP/IP stack. Used after a UDP
- // multicast send to restore the connection's original remote address.
- void mg_multicast_restore(struct mg_connection *c, uint8_t *from);
- // A single HTTP header name/value pair.
- struct mg_http_header {
- struct mg_str name; // Header name, e.g. "Content-Type"
- struct mg_str value; // Header value, e.g. "text/html"
- };
- // Parsed HTTP request or response.
- // Passed as ev_data in MG_EV_HTTP_MSG and MG_EV_HTTP_HDRS.
- // For requests: method="GET", uri="/path", proto="a=1&b=2", proto="HTTP/1.1"
- // For responses: method="HTTP/1.0", uri="200", query="", proto="OK"
- struct mg_http_message {
- struct mg_str method, uri, query, proto; // Request/response line
- struct mg_http_header headers[MG_MAX_HTTP_HEADERS]; // Parsed headers array
- struct mg_str body; // Request or response body
- struct mg_str head; // Raw bytes: request/status line + headers, no body
- struct mg_str message; // Raw bytes: head + body
- };
- // Options for mg_http_serve_dir() and mg_http_serve_file().
- struct mg_http_serve_opts {
- const char *root_dir; // Root directory for serving files, e.g. "/web"
- const char *ssi_pattern; // Pattern for Server-Side Include files, e.g. "#.shtml". NULL disables SSI
- const char *extra_headers; // Extra response headers, e.g. "A: b\r\nC: d\r\n". NULL for none
- const char *mime_types; // Additional MIME types: "ext1=type1,ext2=type2". NULL for defaults only
- const char *page404; // Path to a custom 404 page, e.g. "/404.html". NULL for built-in
- struct mg_fs *fs; // Filesystem to use. NULL defaults to POSIX
- };
- // A single part of a multipart/form-data body, filled by mg_http_next_multipart().
- struct mg_http_part {
- struct mg_str name; // Form field name, from Content-Disposition: name="..."
- struct mg_str filename; // Original filename for file uploads, empty for plain fields
- struct mg_str body; // Part contents, points into the original message buffer
- };
- // Parses HTTP request or response in buffer s/len into hm.
- // Returns number of bytes consumed, 0 if incomplete, -1 on error.
- int mg_http_parse(const char *s, size_t len, struct mg_http_message *);
- // Returns the byte length of HTTP headers in buf (i.e. offset of the body).
- // Returns 0 if headers are incomplete, -1 on error.
- int mg_http_get_request_len(const unsigned char *buf, size_t buf_len);
- // Sends one chunk in HTTP chunked transfer encoding using printf-style fmt.
- // Call with empty fmt ("") to send the terminating zero-length chunk.
- void mg_http_printf_chunk(struct mg_connection *cnn, const char *fmt, ...);
- // Sends one chunk in HTTP chunked transfer encoding from a raw buffer.
- // Call with len=0 to send the terminating zero-length chunk.
- void mg_http_write_chunk(struct mg_connection *c, const char *buf, size_t len);
- // Creates an HTTP server on url, e.g. "http://0.0.0.0:8000".
- //
- // Returns:
- // Listening connection, or NULL on error.
- // Example:
- // mg_http_listen(&mgr, "http://0.0.0.0:8000", fn, NULL);
- // Full examples:
- // tutorials/http/http-server, tutorials/http/*
- // Related APIs:
- // mg_http_reply(), mg_http_serve_dir(), mg_match()
- // Notes:
- // Call mg_mgr_poll() in the main loop. The user-supplied fn event handler
- // receives normal connection events. It also receives MG_EV_HTTP_HDRS when
- // headers are received and MG_EV_HTTP_MSG when the full request is received.
- // ev_data for both HTTP events is struct mg_http_message *.
- struct mg_connection *mg_http_listen(struct mg_mgr *, const char *url,
- mg_event_handler_t fn, void *fn_data);
- // Opens an HTTP client connection to url, e.g. "http://example.org".
- //
- // Returns:
- // Client connection, or NULL on error.
- // Example:
- // mg_http_connect(&mgr, "http://example.org", fn, NULL);
- // Full examples:
- // tutorials/http/http-client, tutorials/http/huge-response
- // Related APIs:
- // mg_printf(), mg_http_status(), mg_http_get_header()
- // Notes:
- // In the user-supplied fn event handler, send the HTTP request on
- // MG_EV_CONNECT. The handler receives normal connection events. It also
- // receives MG_EV_HTTP_HDRS when headers are received and MG_EV_HTTP_MSG when
- // the full response is received. ev_data for both HTTP events is struct
- // mg_http_message *.
- struct mg_connection *mg_http_connect(struct mg_mgr *, const char *url,
- mg_event_handler_t fn, void *fn_data);
- // Serves static files from a directory.
- //
- // Example:
- // struct mg_http_serve_opts o = {.root_dir = "web_root", .fs = &mg_fs_posix};
- // mg_http_serve_dir(c, hm, &o);
- // Full examples:
- // tutorials/http/http-server, tutorials/core/embedded-filesystem
- // Related APIs:
- // mg_http_listen(), mg_http_serve_file(), mg_http_reply(), mg_match()
- // Notes:
- // Call from an MG_EV_HTTP_MSG handler. The uri in hm is mapped under
- // opts->root_dir. Directory listing depends on MG_ENABLE_DIRLIST; SSI uses
- // opts->ssi_pattern when configured.
- void mg_http_serve_dir(struct mg_connection *, struct mg_http_message *hm,
- const struct mg_http_serve_opts *);
- // Serves a single file at path. Call from an MG_EV_HTTP_MSG handler.
- void mg_http_serve_file(struct mg_connection *, struct mg_http_message *hm,
- const char *path, const struct mg_http_serve_opts *);
- // Sends a complete HTTP response with Content-Length.
- //
- // Example:
- // mg_http_reply(c, 200, "Content-Type: application/json\r\n",
- // "{%m:%d}", MG_ESC("temperature"), 123);
- // Full examples:
- // tutorials/http/http-server, tutorials/http/http-restful-server,
- // tutorials/http/device-dashboard
- // Related APIs:
- // mg_http_listen(), mg_printf(), mg_http_printf_chunk(), MG_ESC
- // Notes:
- // headers must end with "\r\n"; pass "" or NULL for no extra headers.
- // body_fmt is printf-style and supports %M/%m custom printers. Use MG_ESC
- // when printing JSON strings.
- void mg_http_reply(struct mg_connection *, int status_code, const char *headers,
- const char *body_fmt, ...);
- // Looks up a request header by name (case-insensitive).
- // Returns a pointer to the mg_str value, or NULL if not found.
- struct mg_str *mg_http_get_header(struct mg_http_message *, const char *name);
- // Extracts a named variable from a query string or form-encoded body (buf).
- // Returns the raw (URL-encoded) value as mg_str, or an empty mg_str if not found.
- // Not NUL-terminated. Use mg_url_decode() to get a decoded string.
- struct mg_str mg_http_var(struct mg_str buf, struct mg_str name);
- // URL-decodes variable name from query string or form body into a NUL-terminated buffer.
- // Returns the length of the decoded value, or negative if not found / buffer too small.
- int mg_http_get_var(const struct mg_str *, const char *name, char *, size_t);
- // URL-decodes s/n into to/to_len. Set form=1 to also decode '+' as space.
- // Returns number of bytes written, or -1 if to buffer is too small.
- int mg_url_decode(const char *s, size_t n, char *to, size_t to_len, int form);
- // URL-encodes s/n into buf/len. Returns number of bytes written.
- size_t mg_url_encode(const char *s, size_t n, char *buf, size_t len);
- // Extracts HTTP credentials into caller-supplied buffers.
- // For Basic auth: fills user (buf1) and password (buf2).
- // For Bearer auth: fills buf1 with "" and buf2 with the token.
- void mg_http_creds(struct mg_http_message *, char *, size_t, char *, size_t);
- // Deprecated API, do not expose
- long mg_http_upload(struct mg_connection *c, struct mg_http_message *hm,
- struct mg_fs *fs, const char *dir, size_t max_size);
- // Streams the raw request body into dir/name via fs. Non-blocking: installs an
- // internal handler and returns immediately. fn is called with NULL on success
- // or an error string on failure.
- void mg_http_start_upload(struct mg_connection *c, struct mg_http_message *hm,
- struct mg_str name, struct mg_str dir,
- struct mg_fs *fs,
- void (*fn)(struct mg_connection *, const char *));
- // Starts an OTA firmware update from an HTTP POST upload.
- // Calls mg_ota_begin/write/end internally; fn is called with NULL on success,
- // or an error string on failure.
- void mg_http_start_ota(struct mg_connection *c, struct mg_http_message *hm,
- void (*fn)(struct mg_connection *, const char *));
- // Sends a 401 Unauthorized response with a Basic Auth WWW-Authenticate challenge.
- void mg_http_bauth(struct mg_connection *, const char *user, const char *pass);
- // Extracts a named parameter from a header value string s.
- // E.g. for s="multipart/form-data; boundary=abc", v="boundary" returns "abc".
- struct mg_str mg_http_get_header_var(struct mg_str s, struct mg_str v);
- // Iterates over parts of a multipart/form-data body.
- //
- // Returns:
- // Offset for the next call, or 0 when there are no more parts.
- // Example:
- // size_t ofs = 0;
- // struct mg_http_part part;
- // while ((ofs = mg_http_next_multipart(hm->body, ofs, &part)) > 0) { ... }
- // Full examples:
- // tutorials/http/file-upload-html-form, tutorials/http/http-server
- // Related APIs:
- // mg_http_listen(), mg_http_start_upload()
- // Notes:
- // Call from an MG_EV_HTTP_MSG handler after the full request body is
- // received. part.name, part.filename, and part.body are zero-copy slices into
- // hm->body and are not NUL-terminated.
- size_t mg_http_next_multipart(struct mg_str, size_t, struct mg_http_part *);
- // Returns the HTTP status code from a parsed response message (e.g. 200, 404).
- int mg_http_status(const struct mg_http_message *hm);
- void mg_http_serve_ssi(struct mg_connection *c, const char *root,
- const char *fullpath);
- // TLS / Security
- // Available TLS backend libraries
- #define MG_TLS_NONE 0 // No TLS support
- #define MG_TLS_MBED 1 // mbedTLS
- #define MG_TLS_OPENSSL 2 // OpenSSL
- #define MG_TLS_WOLFSSL 5 // WolfSSL (based on OpenSSL)
- #define MG_TLS_BUILTIN 3 // Built-in
- #define MG_TLS_CUSTOM 4 // Custom implementation
- #ifndef MG_TLS
- // mongoose_config.h setting. Set MG_TLS to one of the MG_TLS_* values above to
- // select a TLS backend. Defaults to MG_TLS_NONE (no TLS).
- #define MG_TLS MG_TLS_NONE
- #endif
- // TLS options structure passed to mg_tls_init(). All cert/key fields accept
- // PEM strings or DER binary.
- //
- // One-way TLS:
- // server sets `cert` + `key`,
- // client sets `ca` + optionally `name` for hostname verification.
- //
- // Two-way (mutual) TLS: both sides set `ca` + `cert` + `key`.
- //
- // - `ca`: CA certificate. Verifies the peer's certificate.
- // Set on clients to authenticate the server. Set on servers to require
- // and verify a client certificate. If empty, peer is not verified.
- // - `cert`: Our certificate. Required on servers. Also set on clients for
- // mutual TLS.
- // - `key`: Our private key. May equal `cert` when PEM bundles both.
- // - `name`: Server name for SNI and hostname verification. Set on clients.
- // Empty disables hostname verification.
- // - `skip_verification`: Skip certificate and hostname verification.
- // Useful during development; do not use in production.
- struct mg_tls_opts {
- struct mg_str ca; // CA certificate, PEM or DER
- struct mg_str cert; // Our certificate, PEM or DER
- struct mg_str key; // Our private key, PEM or DER
- struct mg_str name; // Server name for SNI + hostname verification
- bool skip_verification; // Skip certificate and hostname verification
- };
- // Initialises TLS on a connection.
- //
- // Example:
- // ```c
- // // Server: one-way TLS
- // if (ev == MG_EV_ACCEPT) {
- // struct mg_tls_opts opts = {.cert = mg_str(s_tls_cert),
- // .key = mg_str(s_tls_key)};
- // mg_tls_init(c, &opts);
- // }
- //
- // // Client: verify server certificate and hostname
- // if (ev == MG_EV_CONNECT) {
- // struct mg_tls_opts opts = {.ca = mg_str(s_tls_ca),
- // .name = mg_str("hostname")};
- // mg_tls_init(c, &opts);
- // }
- // ```
- // Full examples:
- // tutorials/http/http-server, tutorials/http/http-client,
- // tutorials/mqtt/mqtt-client-aws-iot, tutorials/websocket/websocket-client
- // Related APIs:
- // mg_http_listen(), mg_http_connect(), mg_ws_connect(), mg_mqtt_connect()
- // Notes:
- // Call from the user-supplied event handler on MG_EV_ACCEPT for servers or
- // MG_EV_CONNECT for clients, before application data is sent. Servers usually
- // set cert and key. Clients usually set ca and name; name enables SNI and
- // hostname verification.
- void mg_tls_init(struct mg_connection *c, const struct mg_tls_opts *opts);
- // Private API, do not expose
- void mg_tls_free(struct mg_connection *);
- long mg_tls_send(struct mg_connection *, const void *buf, size_t len);
- long mg_tls_recv(struct mg_connection *, void *buf, size_t len);
- size_t mg_tls_pending(struct mg_connection *);
- void mg_tls_flush(struct mg_connection *);
- void mg_tls_handshake(struct mg_connection *);
- void mg_tls_ctx_init(struct mg_mgr *);
- void mg_tls_ctx_free(struct mg_mgr *);
- #define MG_IS_DER(buf) (((uint8_t *) (buf))[0] == 0x30) // DER begins with 0x30
- #if MG_TLS == MG_TLS_BUILTIN
- // Extracts a 32-byte P-256 private scalar from EC PRIVATE KEY or PKCS#8 PRIVATE
- // KEY input. Accepts PEM or DER. Returns key size, or 0 on error.
- size_t mg_uecc_parse_private_key(struct mg_str key, uint8_t *buf, size_t len);
- #endif
- // Low-level IO primitives used by TLS layer
- enum { MG_IO_ERR = -1, MG_IO_WAIT = -2 };
- long mg_io_send(struct mg_connection *c, const void *buf, size_t len);
- long mg_io_recv(struct mg_connection *c, void *buf, size_t len);
- #ifndef TLS_X15519_H
- #define TLS_X15519_H
- #define X25519_BYTES 32
- extern const uint8_t X25519_BASE_POINT[X25519_BYTES];
- int mg_tls_x25519(uint8_t out[X25519_BYTES], const uint8_t scalar[X25519_BYTES],
- const uint8_t x1[X25519_BYTES], int clamp);
- #endif /* TLS_X15519_H */
- /******************************************************************************
- *
- * THIS SOURCE CODE IS HEREBY PLACED INTO THE PUBLIC DOMAIN FOR THE GOOD OF ALL
- *
- * This is a simple and straightforward implementation of AES-GCM authenticated
- * encryption. The focus of this work was correctness & accuracy. It is written
- * in straight 'C' without any particular focus upon optimization or speed. It
- * should be endian (memory byte order) neutral since the few places that care
- * are handled explicitly.
- *
- * This implementation of AES-GCM was created by Steven M. Gibson of GRC.com.
- *
- * It is intended for general purpose use, but was written in support of GRC's
- * reference implementation of the SQRL (Secure Quick Reliable Login) client.
- *
- * See: http://csrc.nist.gov/publications/nistpubs/800-38D/SP-800-38D.pdf
- * http://csrc.nist.gov/groups/ST/toolkit/BCM/documents/proposedmodes/ \
- * gcm/gcm-revised-spec.pdf
- *
- * NO COPYRIGHT IS CLAIMED IN THIS WORK, HOWEVER, NEITHER IS ANY WARRANTY MADE
- * REGARDING ITS FITNESS FOR ANY PARTICULAR PURPOSE. USE IT AT YOUR OWN RISK.
- *
- *******************************************************************************/
- #ifndef TLS_AES128_H
- #define TLS_AES128_H
- /******************************************************************************
- * AES_CONTEXT : cipher context / holds inter-call data
- ******************************************************************************/
- typedef struct {
- int mode; // 1 for Encryption, 0 for Decryption
- int rounds; // keysize-based rounds count
- uint32_t *rk; // pointer to current round key
- uint32_t buf[68]; // key expansion buffer
- } aes_context;
- #define GCM_AUTH_FAILURE 0x55555555 // authentication failure
- /******************************************************************************
- * GCM_CONTEXT : MUST be called once before ANY use of this library
- ******************************************************************************/
- int mg_gcm_initialize(void);
- //
- // aes-gcm.h
- // MKo
- //
- // Created by Markus Kosmal on 20/11/14.
- //
- //
- int mg_aes_gcm_encrypt(unsigned char *output, const unsigned char *input,
- size_t input_length, const unsigned char *key,
- const size_t key_len, const unsigned char *iv,
- const size_t iv_len, unsigned char *aead,
- size_t aead_len, unsigned char *tag,
- const size_t tag_len);
- int mg_aes_gcm_decrypt(unsigned char *output, const unsigned char *input,
- size_t input_length, const unsigned char *key,
- const size_t key_len, const unsigned char *iv,
- const size_t iv_len, unsigned char *aead,
- size_t aead_len, const unsigned char *tag,
- const size_t tag_len);
- #endif /* TLS_AES128_H */
- // End of aes128 PD
- /* Copyright 2014, Kenneth MacKay. Licensed under the BSD 2-clause license. */
- #ifndef _UECC_H_
- #define _UECC_H_
- /* Platform selection options.
- If MG_UECC_PLATFORM is not defined, the code will try to guess it based on
- compiler macros. Possible values for MG_UECC_PLATFORM are defined below: */
- #define mg_uecc_arch_other 0
- #define mg_uecc_x86 1
- #define mg_uecc_x86_64 2
- #define mg_uecc_arm 3
- #define mg_uecc_arm_thumb 4
- #define mg_uecc_arm_thumb2 5
- #define mg_uecc_arm64 6
- #define mg_uecc_avr 7
- /* If desired, you can define MG_UECC_WORD_SIZE as appropriate for your platform
- (1, 4, or 8 bytes). If MG_UECC_WORD_SIZE is not explicitly defined then it will
- be automatically set based on your platform. */
- /* Optimization level; trade speed for code size.
- Larger values produce code that is faster but larger.
- Currently supported values are 0 - 4; 0 is unusably slow for most
- applications. Optimization level 4 currently only has an effect ARM platforms
- where more than one curve is enabled. */
- #ifndef MG_UECC_OPTIMIZATION_LEVEL
- #define MG_UECC_OPTIMIZATION_LEVEL 2
- #endif
- /* MG_UECC_SQUARE_FUNC - If enabled (defined as nonzero), this will cause a
- specific function to be used for (scalar) squaring instead of the generic
- multiplication function. This can make things faster somewhat faster, but
- increases the code size. */
- #ifndef MG_UECC_SQUARE_FUNC
- #define MG_UECC_SQUARE_FUNC 0
- #endif
- /* MG_UECC_VLI_NATIVE_LITTLE_ENDIAN - If enabled (defined as nonzero), this will
- switch to native little-endian format for *all* arrays passed in and out of the
- public API. This includes public and private keys, shared secrets, signatures
- and message hashes. Using this switch reduces the amount of call stack memory
- used by uECC, since less intermediate translations are required. Note that this
- will *only* work on native little-endian processors and it will treat the
- uint8_t arrays passed into the public API as word arrays, therefore requiring
- the provided byte arrays to be word aligned on architectures that do not support
- unaligned accesses. IMPORTANT: Keys and signatures generated with
- MG_UECC_VLI_NATIVE_LITTLE_ENDIAN=1 are incompatible with keys and signatures
- generated with MG_UECC_VLI_NATIVE_LITTLE_ENDIAN=0; all parties must use the same
- endianness. */
- #ifndef MG_UECC_VLI_NATIVE_LITTLE_ENDIAN
- #define MG_UECC_VLI_NATIVE_LITTLE_ENDIAN 0
- #endif
- /* Curve support selection. Set to 0 to remove that curve. */
- #ifndef MG_UECC_SUPPORTS_secp160r1
- #define MG_UECC_SUPPORTS_secp160r1 0
- #endif
- #ifndef MG_UECC_SUPPORTS_secp192r1
- #define MG_UECC_SUPPORTS_secp192r1 0
- #endif
- #ifndef MG_UECC_SUPPORTS_secp224r1
- #define MG_UECC_SUPPORTS_secp224r1 0
- #endif
- #ifndef MG_UECC_SUPPORTS_secp256r1
- #define MG_UECC_SUPPORTS_secp256r1 1
- #endif
- #ifndef MG_UECC_SUPPORTS_secp256k1
- #define MG_UECC_SUPPORTS_secp256k1 0
- #endif
- #ifndef MG_UECC_SUPPORTS_secp384r1
- #define MG_UECC_SUPPORTS_secp384r1 1
- #endif
- /* Specifies whether compressed point format is supported.
- Set to 0 to disable point compression/decompression functions. */
- #ifndef MG_UECC_SUPPORT_COMPRESSED_POINT
- #define MG_UECC_SUPPORT_COMPRESSED_POINT 1
- #endif
- struct MG_UECC_Curve_t;
- typedef const struct MG_UECC_Curve_t *MG_UECC_Curve;
- #ifdef __cplusplus
- extern "C" {
- #endif
- #if MG_UECC_SUPPORTS_secp160r1
- MG_UECC_Curve mg_uecc_secp160r1(void);
- #endif
- #if MG_UECC_SUPPORTS_secp192r1
- MG_UECC_Curve mg_uecc_secp192r1(void);
- #endif
- #if MG_UECC_SUPPORTS_secp224r1
- MG_UECC_Curve mg_uecc_secp224r1(void);
- #endif
- #if MG_UECC_SUPPORTS_secp256r1
- MG_UECC_Curve mg_uecc_secp256r1(void);
- #endif
- #if MG_UECC_SUPPORTS_secp256k1
- MG_UECC_Curve mg_uecc_secp256k1(void);
- #endif
- #if MG_UECC_SUPPORTS_secp384r1
- MG_UECC_Curve mg_uecc_secp384r1(void);
- #endif
- /* MG_UECC_RNG_Function type
- The RNG function should fill 'size' random bytes into 'dest'. It should return 1
- if 'dest' was filled with random data, or 0 if the random data could not be
- generated. The filled-in values should be either truly random, or from a
- cryptographically-secure PRNG.
- A correctly functioning RNG is required before calling mg_uecc_make_key() or
- mg_uecc_sign().
- Setting a correctly functioning RNG function improves the resistance to
- side-channel attacks for mg_uecc_shared_secret() and
- mg_uecc_sign_deterministic().
- */
- typedef int (*MG_UECC_RNG_Function)(uint8_t *dest, unsigned size);
- // Mongoose: mg_uecc_make_key() and mg_uecc_sign() use mg_random() when no
- // explicit uECC RNG is installed. If mg_random() cannot provide a strong source,
- // those operations fail. Deterministic signing works without RNG, but only an
- // explicit uECC RNG enables its optional side-channel blinding.
- /* mg_uecc_set_rng() function.
- Set the function that will be used to generate random bytes. The RNG function
- should return 1 if the random data was generated, or 0 if the random data could
- not be generated.
- Mongoose: this overrides the default mg_random() fallback used by
- mg_uecc_make_key() and mg_uecc_sign(). Do not call mg_uecc_set_rng() unless the
- application must provide its own cryptographic RNG.
- Inputs:
- rng_function - The function that will be used to generate random bytes.
- */
- void mg_uecc_set_rng(MG_UECC_RNG_Function rng_function);
- /* mg_uecc_get_rng() function.
- Returns the function that will be used to generate random bytes.
- */
- MG_UECC_RNG_Function mg_uecc_get_rng(void);
- /* mg_uecc_curve_private_key_size() function.
- Returns the size of a private key for the curve in bytes.
- */
- int mg_uecc_curve_private_key_size(MG_UECC_Curve curve);
- /* mg_uecc_curve_public_key_size() function.
- Returns the size of a public key for the curve in bytes.
- */
- int mg_uecc_curve_public_key_size(MG_UECC_Curve curve);
- /* mg_uecc_make_key() function.
- Create a public/private key pair.
- Outputs:
- public_key - Will be filled in with the public key. Must be at least 2 *
- the curve size (in bytes) long. For example, if the curve is secp256r1,
- public_key must be 64 bytes long. private_key - Will be filled in with the
- private key. Must be as long as the curve order; this is typically the same as
- the curve size, except for secp160r1. For example, if the curve is secp256r1,
- private_key must be 32 bytes long.
- For secp160r1, private_key must be 21 bytes long! Note that
- the first byte will almost always be 0 (there is about a 1 in 2^80 chance of it
- being non-zero).
- Returns 1 if the key pair was generated successfully, 0 if an error occurred.
- */
- int mg_uecc_make_key(uint8_t *public_key, uint8_t *private_key,
- MG_UECC_Curve curve);
- /* mg_uecc_shared_secret() function.
- Compute a shared secret given your secret key and someone else's public key. If
- the public key is not from a trusted source and has not been previously
- verified, you should verify it first using mg_uecc_valid_public_key(). Note: It
- is recommended that you hash the result of mg_uecc_shared_secret() before using
- it for symmetric encryption or HMAC.
- Inputs:
- public_key - The public key of the remote party.
- private_key - Your private key.
- Outputs:
- secret - Will be filled in with the shared secret value. Must be the same
- size as the curve size; for example, if the curve is secp256r1, secret must be
- 32 bytes long.
- Returns 1 if the shared secret was generated successfully, 0 if an error
- occurred.
- */
- int mg_uecc_shared_secret(const uint8_t *public_key, const uint8_t *private_key,
- uint8_t *secret, MG_UECC_Curve curve);
- #if MG_UECC_SUPPORT_COMPRESSED_POINT
- /* mg_uecc_compress() function.
- Compress a public key.
- Inputs:
- public_key - The public key to compress.
- Outputs:
- compressed - Will be filled in with the compressed public key. Must be at
- least (curve size + 1) bytes long; for example, if the curve is secp256r1,
- compressed must be 33 bytes long.
- */
- void mg_uecc_compress(const uint8_t *public_key, uint8_t *compressed,
- MG_UECC_Curve curve);
- /* mg_uecc_decompress() function.
- Decompress a compressed public key.
- Inputs:
- compressed - The compressed public key.
- Outputs:
- public_key - Will be filled in with the decompressed public key.
- */
- void mg_uecc_decompress(const uint8_t *compressed, uint8_t *public_key,
- MG_UECC_Curve curve);
- #endif /* MG_UECC_SUPPORT_COMPRESSED_POINT */
- /* mg_uecc_valid_public_key() function.
- Check to see if a public key is valid.
- Note that you are not required to check for a valid public key before using any
- other uECC functions. However, you may wish to avoid spending CPU time computing
- a shared secret or verifying a signature using an invalid public key.
- Inputs:
- public_key - The public key to check.
- Returns 1 if the public key is valid, 0 if it is invalid.
- */
- int mg_uecc_valid_public_key(const uint8_t *public_key, MG_UECC_Curve curve);
- /* mg_uecc_compute_public_key() function.
- Compute the corresponding public key for a private key.
- Inputs:
- private_key - The private key to compute the public key for
- Outputs:
- public_key - Will be filled in with the corresponding public key
- Returns 1 if the key was computed successfully, 0 if an error occurred.
- */
- int mg_uecc_compute_public_key(const uint8_t *private_key, uint8_t *public_key,
- MG_UECC_Curve curve);
- /* mg_uecc_sign() function.
- Generate an ECDSA signature for a given hash value.
- Usage: Compute a hash of the data you wish to sign (SHA-2 is recommended) and
- pass it in to this function along with your private key.
- Inputs:
- private_key - Your private key.
- message_hash - The hash of the message to sign.
- hash_size - The size of message_hash in bytes.
- Outputs:
- signature - Will be filled in with the signature value. Must be at least 2 *
- curve size long. For example, if the curve is secp256r1, signature must be 64
- bytes long.
- Returns 1 if the signature generated successfully, 0 if an error occurred.
- */
- int mg_uecc_sign(const uint8_t *private_key, const uint8_t *message_hash,
- unsigned hash_size, uint8_t *signature, MG_UECC_Curve curve);
- /* MG_UECC_HashContext structure.
- This is used to pass in an arbitrary hash function to
- mg_uecc_sign_deterministic(). The structure will be used for multiple hash
- computations; each time a new hash is computed, init_hash() will be called,
- followed by one or more calls to update_hash(), and finally a call to
- finish_hash() to produce the resulting hash.
- The intention is that you will create a structure that includes
- MG_UECC_HashContext followed by any hash-specific data. For example:
- typedef struct SHA256_HashContext {
- MG_UECC_HashContext uECC;
- SHA256_CTX ctx;
- } SHA256_HashContext;
- void init_SHA256(MG_UECC_HashContext *base) {
- SHA256_HashContext *context = (SHA256_HashContext *)base;
- SHA256_Init(&context->ctx);
- }
- void update_SHA256(MG_UECC_HashContext *base,
- const uint8_t *message,
- unsigned message_size) {
- SHA256_HashContext *context = (SHA256_HashContext *)base;
- SHA256_Update(&context->ctx, message, message_size);
- }
- void finish_SHA256(MG_UECC_HashContext *base, uint8_t *hash_result) {
- SHA256_HashContext *context = (SHA256_HashContext *)base;
- SHA256_Final(hash_result, &context->ctx);
- }
- ... when signing ...
- {
- uint8_t tmp[32 + 32 + 64];
- SHA256_HashContext ctx = {{&init_SHA256, &update_SHA256, &finish_SHA256, 64,
- 32, tmp}}; mg_uecc_sign_deterministic(key, message_hash, &ctx.uECC, signature);
- }
- */
- typedef struct MG_UECC_HashContext {
- void (*init_hash)(const struct MG_UECC_HashContext *context);
- void (*update_hash)(const struct MG_UECC_HashContext *context,
- const uint8_t *message, unsigned message_size);
- void (*finish_hash)(const struct MG_UECC_HashContext *context,
- uint8_t *hash_result);
- unsigned
- block_size; /* Hash function block size in bytes, eg 64 for SHA-256. */
- unsigned
- result_size; /* Hash function result size in bytes, eg 32 for SHA-256. */
- uint8_t *tmp; /* Must point to a buffer of at least (2 * result_size +
- block_size) bytes. */
- } MG_UECC_HashContext;
- /* mg_uecc_sign_deterministic() function.
- Generate an ECDSA signature for a given hash value, using a deterministic
- algorithm (see RFC 6979). You do not need to set the RNG using mg_uecc_set_rng()
- before calling this function; however, if the RNG is defined it will improve
- resistance to side-channel attacks.
- Usage: Compute a hash of the data you wish to sign (SHA-2 is recommended) and
- pass it to this function along with your private key and a hash context. Note
- that the message_hash does not need to be computed with the same hash function
- used by hash_context.
- Inputs:
- private_key - Your private key.
- message_hash - The hash of the message to sign.
- hash_size - The size of message_hash in bytes.
- hash_context - A hash context to use.
- Outputs:
- signature - Will be filled in with the signature value.
- Returns 1 if the signature generated successfully, 0 if an error occurred.
- */
- int mg_uecc_sign_deterministic(const uint8_t *private_key,
- const uint8_t *message_hash, unsigned hash_size,
- const MG_UECC_HashContext *hash_context,
- uint8_t *signature, MG_UECC_Curve curve);
- /* mg_uecc_verify() function.
- Verify an ECDSA signature.
- Usage: Compute the hash of the signed data using the same hash as the signer and
- pass it to this function along with the signer's public key and the signature
- values (r and s).
- Inputs:
- public_key - The signer's public key.
- message_hash - The hash of the signed data.
- hash_size - The size of message_hash in bytes.
- signature - The signature value.
- Returns 1 if the signature is valid, 0 if it is invalid.
- */
- int mg_uecc_verify(const uint8_t *public_key, const uint8_t *message_hash,
- unsigned hash_size, const uint8_t *signature,
- MG_UECC_Curve curve);
- #ifdef __cplusplus
- } /* end of extern "C" */
- #endif
- #endif /* _UECC_H_ */
- /* Copyright 2015, Kenneth MacKay. Licensed under the BSD 2-clause license. */
- #ifndef _UECC_TYPES_H_
- #define _UECC_TYPES_H_
- #ifndef MG_UECC_PLATFORM
- #if defined(__AVR__) && __AVR__
- #define MG_UECC_PLATFORM mg_uecc_avr
- #elif defined(__thumb2__) || \
- defined(_M_ARMT) /* I think MSVC only supports Thumb-2 targets */
- #define MG_UECC_PLATFORM mg_uecc_arm_thumb2
- #elif defined(__thumb__)
- #define MG_UECC_PLATFORM mg_uecc_arm_thumb
- #elif defined(__arm__) || defined(_M_ARM)
- #define MG_UECC_PLATFORM mg_uecc_arm
- #elif defined(__aarch64__)
- #define MG_UECC_PLATFORM mg_uecc_arm64
- #elif defined(__i386__) || defined(_M_IX86) || defined(_X86_) || \
- defined(__I86__)
- #define MG_UECC_PLATFORM mg_uecc_x86
- #elif defined(__amd64__) || defined(_M_X64)
- #define MG_UECC_PLATFORM mg_uecc_x86_64
- #else
- #define MG_UECC_PLATFORM mg_uecc_arch_other
- #endif
- #endif
- #ifndef MG_UECC_ARM_USE_UMAAL
- #if (MG_UECC_PLATFORM == mg_uecc_arm) && (__ARM_ARCH >= 6)
- #define MG_UECC_ARM_USE_UMAAL 1
- #elif (MG_UECC_PLATFORM == mg_uecc_arm_thumb2) && (__ARM_ARCH >= 6) && \
- (!defined(__ARM_ARCH_7M__) || !__ARM_ARCH_7M__)
- #define MG_UECC_ARM_USE_UMAAL 1
- #else
- #define MG_UECC_ARM_USE_UMAAL 0
- #endif
- #endif
- #ifndef MG_UECC_WORD_SIZE
- #if MG_UECC_PLATFORM == mg_uecc_avr
- #define MG_UECC_WORD_SIZE 1
- #elif (MG_UECC_PLATFORM == mg_uecc_x86_64 || MG_UECC_PLATFORM == mg_uecc_arm64)
- #define MG_UECC_WORD_SIZE 8
- #else
- #define MG_UECC_WORD_SIZE 4
- #endif
- #endif
- #if (MG_UECC_WORD_SIZE != 1) && (MG_UECC_WORD_SIZE != 4) && \
- (MG_UECC_WORD_SIZE != 8)
- #error "Unsupported value for MG_UECC_WORD_SIZE"
- #endif
- #if ((MG_UECC_PLATFORM == mg_uecc_avr) && (MG_UECC_WORD_SIZE != 1))
- #pragma message("MG_UECC_WORD_SIZE must be 1 for AVR")
- #undef MG_UECC_WORD_SIZE
- #define MG_UECC_WORD_SIZE 1
- #endif
- #if ((MG_UECC_PLATFORM == mg_uecc_arm || \
- MG_UECC_PLATFORM == mg_uecc_arm_thumb || \
- MG_UECC_PLATFORM == mg_uecc_arm_thumb2) && \
- (MG_UECC_WORD_SIZE != 4))
- #pragma message("MG_UECC_WORD_SIZE must be 4 for ARM")
- #undef MG_UECC_WORD_SIZE
- #define MG_UECC_WORD_SIZE 4
- #endif
- typedef int8_t wordcount_t;
- typedef int16_t bitcount_t;
- typedef int8_t cmpresult_t;
- #if (MG_UECC_WORD_SIZE == 1)
- typedef uint8_t mg_uecc_word_t;
- typedef uint16_t mg_uecc_dword_t;
- #define HIGH_BIT_SET 0x80
- #define MG_UECC_WORD_BITS 8
- #define MG_UECC_WORD_BITS_SHIFT 3
- #define MG_UECC_WORD_BITS_MASK 0x07
- #elif (MG_UECC_WORD_SIZE == 4)
- typedef uint32_t mg_uecc_word_t;
- typedef uint64_t mg_uecc_dword_t;
- #define HIGH_BIT_SET 0x80000000
- #define MG_UECC_WORD_BITS 32
- #define MG_UECC_WORD_BITS_SHIFT 5
- #define MG_UECC_WORD_BITS_MASK 0x01F
- #elif (MG_UECC_WORD_SIZE == 8)
- typedef uint64_t mg_uecc_word_t;
- #define HIGH_BIT_SET 0x8000000000000000U
- #define MG_UECC_WORD_BITS 64
- #define MG_UECC_WORD_BITS_SHIFT 6
- #define MG_UECC_WORD_BITS_MASK 0x03F
- #endif /* MG_UECC_WORD_SIZE */
- #endif /* _UECC_TYPES_H_ */
- /* Copyright 2015, Kenneth MacKay. Licensed under the BSD 2-clause license. */
- #ifndef _UECC_VLI_H_
- #define _UECC_VLI_H_
- //
- //
- /* Functions for raw large-integer manipulation. These are only available
- if uECC.c is compiled with MG_UECC_ENABLE_VLI_API defined to 1. */
- #ifndef MG_UECC_ENABLE_VLI_API
- #define MG_UECC_ENABLE_VLI_API 0
- #endif
- #ifdef __cplusplus
- extern "C" {
- #endif
- #if MG_UECC_ENABLE_VLI_API
- void mg_uecc_vli_clear(mg_uecc_word_t *vli, wordcount_t num_words);
- /* Constant-time comparison to zero - secure way to compare long integers */
- /* Returns 1 if vli == 0, 0 otherwise. */
- mg_uecc_word_t mg_uecc_vli_isZero(const mg_uecc_word_t *vli,
- wordcount_t num_words);
- /* Returns nonzero if bit 'bit' of vli is set. */
- mg_uecc_word_t mg_uecc_vli_testBit(const mg_uecc_word_t *vli, bitcount_t bit);
- /* Counts the number of bits required to represent vli. */
- bitcount_t mg_uecc_vli_numBits(const mg_uecc_word_t *vli,
- const wordcount_t max_words);
- /* Sets dest = src. */
- void mg_uecc_vli_set(mg_uecc_word_t *dest, const mg_uecc_word_t *src,
- wordcount_t num_words);
- /* Constant-time comparison function - secure way to compare long integers */
- /* Returns one if left == right, zero otherwise */
- mg_uecc_word_t mg_uecc_vli_equal(const mg_uecc_word_t *left,
- const mg_uecc_word_t *right,
- wordcount_t num_words);
- /* Constant-time comparison function - secure way to compare long integers */
- /* Returns sign of left - right, in constant time. */
- cmpresult_t mg_uecc_vli_cmp(const mg_uecc_word_t *left,
- const mg_uecc_word_t *right, wordcount_t num_words);
- /* Computes vli = vli >> 1. */
- void mg_uecc_vli_rshift1(mg_uecc_word_t *vli, wordcount_t num_words);
- /* Computes result = left + right, returning carry. Can modify in place. */
- mg_uecc_word_t mg_uecc_vli_add(mg_uecc_word_t *result,
- const mg_uecc_word_t *left,
- const mg_uecc_word_t *right,
- wordcount_t num_words);
- /* Computes result = left - right, returning borrow. Can modify in place. */
- mg_uecc_word_t mg_uecc_vli_sub(mg_uecc_word_t *result,
- const mg_uecc_word_t *left,
- const mg_uecc_word_t *right,
- wordcount_t num_words);
- /* Computes result = left * right. Result must be 2 * num_words long. */
- void mg_uecc_vli_mult(mg_uecc_word_t *result, const mg_uecc_word_t *left,
- const mg_uecc_word_t *right, wordcount_t num_words);
- /* Computes result = left^2. Result must be 2 * num_words long. */
- void mg_uecc_vli_square(mg_uecc_word_t *result, const mg_uecc_word_t *left,
- wordcount_t num_words);
- /* Computes result = (left + right) % mod.
- Assumes that left < mod and right < mod, and that result does not overlap
- mod. */
- void mg_uecc_vli_modAdd(mg_uecc_word_t *result, const mg_uecc_word_t *left,
- const mg_uecc_word_t *right, const mg_uecc_word_t *mod,
- wordcount_t num_words);
- /* Computes result = (left - right) % mod.
- Assumes that left < mod and right < mod, and that result does not overlap
- mod. */
- void mg_uecc_vli_modSub(mg_uecc_word_t *result, const mg_uecc_word_t *left,
- const mg_uecc_word_t *right, const mg_uecc_word_t *mod,
- wordcount_t num_words);
- /* Computes result = product % mod, where product is 2N words long.
- Currently only designed to work for mod == curve->p or curve_n. */
- void mg_uecc_vli_mmod(mg_uecc_word_t *result, mg_uecc_word_t *product,
- const mg_uecc_word_t *mod, wordcount_t num_words);
- /* Calculates result = product (mod curve->p), where product is up to
- 2 * curve->num_words long. */
- void mg_uecc_vli_mmod_fast(mg_uecc_word_t *result, mg_uecc_word_t *product,
- MG_UECC_Curve curve);
- /* Computes result = (left * right) % mod.
- Currently only designed to work for mod == curve->p or curve_n. */
- void mg_uecc_vli_modMult(mg_uecc_word_t *result, const mg_uecc_word_t *left,
- const mg_uecc_word_t *right, const mg_uecc_word_t *mod,
- wordcount_t num_words);
- /* Computes result = (left * right) % curve->p. */
- void mg_uecc_vli_modMult_fast(mg_uecc_word_t *result,
- const mg_uecc_word_t *left,
- const mg_uecc_word_t *right, MG_UECC_Curve curve);
- /* Computes result = left^2 % mod.
- Currently only designed to work for mod == curve->p or curve_n. */
- void mg_uecc_vli_modSquare(mg_uecc_word_t *result, const mg_uecc_word_t *left,
- const mg_uecc_word_t *mod, wordcount_t num_words);
- /* Computes result = left^2 % curve->p. */
- void mg_uecc_vli_modSquare_fast(mg_uecc_word_t *result,
- const mg_uecc_word_t *left,
- MG_UECC_Curve curve);
- /* Computes result = (1 / input) % mod.*/
- void mg_uecc_vli_modInv(mg_uecc_word_t *result, const mg_uecc_word_t *input,
- const mg_uecc_word_t *mod, wordcount_t num_words);
- #if MG_UECC_SUPPORT_COMPRESSED_POINT
- /* Calculates a = sqrt(a) (mod curve->p) */
- void mg_uecc_vli_mod_sqrt(mg_uecc_word_t *a, MG_UECC_Curve curve);
- #endif
- /* Converts an integer in uECC native format to big-endian bytes. */
- void mg_uecc_vli_nativeToBytes(uint8_t *bytes, int num_bytes,
- const mg_uecc_word_t *native);
- /* Converts big-endian bytes to an integer in uECC native format. */
- void mg_uecc_vli_bytesToNative(mg_uecc_word_t *native, const uint8_t *bytes,
- int num_bytes);
- unsigned mg_uecc_curve_num_words(MG_UECC_Curve curve);
- unsigned mg_uecc_curve_num_bytes(MG_UECC_Curve curve);
- unsigned mg_uecc_curve_num_bits(MG_UECC_Curve curve);
- unsigned mg_uecc_curve_num_n_words(MG_UECC_Curve curve);
- unsigned mg_uecc_curve_num_n_bytes(MG_UECC_Curve curve);
- unsigned mg_uecc_curve_num_n_bits(MG_UECC_Curve curve);
- const mg_uecc_word_t *mg_uecc_curve_p(MG_UECC_Curve curve);
- const mg_uecc_word_t *mg_uecc_curve_n(MG_UECC_Curve curve);
- const mg_uecc_word_t *mg_uecc_curve_G(MG_UECC_Curve curve);
- const mg_uecc_word_t *mg_uecc_curve_b(MG_UECC_Curve curve);
- int mg_uecc_valid_point(const mg_uecc_word_t *point, MG_UECC_Curve curve);
- /* Multiplies a point by a scalar. Points are represented by the X coordinate
- followed by the Y coordinate in the same array, both coordinates are
- curve->num_words long. Note that scalar must be curve->num_n_words long (NOT
- curve->num_words). */
- void mg_uecc_point_mult(mg_uecc_word_t *result, const mg_uecc_word_t *point,
- const mg_uecc_word_t *scalar, MG_UECC_Curve curve);
- /* Generates a random integer in the range 0 < random < top.
- Both random and top have num_words words. */
- int mg_uecc_generate_random_int(mg_uecc_word_t *random,
- const mg_uecc_word_t *top,
- wordcount_t num_words);
- #endif /* MG_UECC_ENABLE_VLI_API */
- #ifdef __cplusplus
- } /* end of extern "C" */
- #endif
- #endif /* _UECC_VLI_H_ */
- // End of uecc BSD-2
- // portable8439 v1.0.1
- // Source: https://github.com/DavyLandman/portable8439
- // Licensed under CC0-1.0
- // Contains poly1305-donna e6ad6e091d30d7f4ec2d4f978be1fcfcbce72781 (Public
- // Domain)
- #if MG_TLS == MG_TLS_BUILTIN && MG_ENABLE_CHACHA20
- #ifndef __PORTABLE_8439_H
- #define __PORTABLE_8439_H
- #if defined(__cplusplus)
- extern "C" {
- #endif
- // provide your own decl specificier like -DPORTABLE_8439_DECL=ICACHE_RAM_ATTR
- #ifndef PORTABLE_8439_DECL
- #define PORTABLE_8439_DECL
- #endif
- /*
- This library implements RFC 8439 a.k.a. ChaCha20-Poly1305 AEAD
- You can use this library to avoid attackers mutating or reusing your
- encrypted messages. This does assume you never reuse a nonce+key pair and,
- if possible, carefully pick your associated data.
- */
- /* Make sure we are either nested in C++ or running in a C99+ compiler
- #if !defined(__cplusplus) && !defined(_MSC_VER) && \
- (!defined(__STDC_VERSION__) || __STDC_VERSION__ < 199901L)
- #error "C99 or newer required"
- #endif */
- // #if CHAR_BIT > 8
- // # error "Systems without native octals not suppoted"
- // #endif
- #if defined(_MSC_VER) || defined(__cplusplus)
- // add restrict support is possible
- #if (defined(_MSC_VER) && _MSC_VER >= 1900) || defined(__clang__) || \
- defined(__GNUC__)
- #define restrict __restrict
- #else
- #define restrict
- #endif
- #endif
- #define RFC_8439_TAG_SIZE (16)
- #define RFC_8439_KEY_SIZE (32)
- #define RFC_8439_NONCE_SIZE (12)
- /*
- Encrypt/Seal plain text bytes into a cipher text that can only be
- decrypted by knowing the key, nonce and associated data.
- input:
- - key: RFC_8439_KEY_SIZE bytes that all parties have agreed
- upon beforehand
- - nonce: RFC_8439_NONCE_SIZE bytes that should never be repeated
- for the same key. A counter or a pseudo-random value are fine.
- - ad: associated data to include with calculating the tag of the
- cipher text. Can be null for empty.
- - plain_text: data to be encrypted, pointer + size should not overlap
- with cipher_text pointer
- output:
- - cipher_text: encrypted plain_text with a tag appended. Make sure to
- allocate at least plain_text_size + RFC_8439_TAG_SIZE
- returns:
- - size of bytes written to cipher_text, can be -1 if overlapping
- pointers are passed for plain_text and cipher_text
- */
- PORTABLE_8439_DECL size_t mg_chacha20_poly1305_encrypt(
- uint8_t *restrict cipher_text, const uint8_t key[RFC_8439_KEY_SIZE],
- const uint8_t nonce[RFC_8439_NONCE_SIZE], const uint8_t *restrict ad,
- size_t ad_size, const uint8_t *restrict plain_text, size_t plain_text_size);
- /*
- Decrypt/unseal cipher text given the right key, nonce, and additional data.
- input:
- - key: RFC_8439_KEY_SIZE bytes that all parties have agreed
- upon beforehand
- - nonce: RFC_8439_NONCE_SIZE bytes that should never be repeated for
- the same key. A counter or a pseudo-random value are fine.
- - ad: associated data to include with calculating the tag of the
- cipher text. Can be null for empty.
- - cipher_text: encrypted message.
- output:
- - plain_text: data to be encrypted, pointer + size should not overlap
- with cipher_text pointer, leave at least enough room for
- cipher_text_size - RFC_8439_TAG_SIZE
- returns:
- - size of bytes written to plain_text, -1 signals either:
- - incorrect key/nonce/ad
- - corrupted cipher_text
- - overlapping pointers are passed for plain_text and cipher_text
- */
- PORTABLE_8439_DECL size_t mg_chacha20_poly1305_decrypt(
- uint8_t *restrict plain_text, const uint8_t key[RFC_8439_KEY_SIZE],
- const uint8_t nonce[RFC_8439_NONCE_SIZE],
- const uint8_t *restrict ad, size_t ad_size,
- const uint8_t *restrict cipher_text, size_t cipher_text_size);
- #if defined(__cplusplus)
- }
- #endif
- #endif
- #endif
- #ifndef TLS_RSA_H
- #define TLS_RSA_H
- int mg_rsa_mod_pow(const uint8_t *mod, size_t modsz, const uint8_t *exp, size_t expsz, const uint8_t *msg, size_t msgsz, uint8_t *out, size_t outsz);
- int mg_rsa_crt_sign(const uint8_t *em, size_t em_len,
- const uint8_t *dP, size_t dP_len,
- const uint8_t *dQ, size_t dQ_len,
- const uint8_t *p, size_t p_len,
- const uint8_t *q, size_t q_len,
- const uint8_t *qInv, size_t qInv_len,
- uint8_t *signature, size_t sig_len);
- bool mg_rsa_pkcs_verify(const uint8_t *em, size_t nlen, const uint8_t *hash,
- size_t hashlen);
- bool mg_rsa_verify(const uint8_t *em, size_t nlen, const uint8_t *mhash);
- #endif // TLS_RSA_H
- #if MG_TLS == MG_TLS_MBED
- #include <mbedtls/debug.h>
- #include <mbedtls/error.h>
- #include <mbedtls/net_sockets.h>
- #include <mbedtls/ssl.h>
- #include <mbedtls/ssl_ticket.h>
- struct mg_tls_ctx {
- int dummy;
- #ifdef MBEDTLS_SSL_SESSION_TICKETS
- mbedtls_ssl_ticket_context tickets;
- #endif
- };
- struct mg_tls {
- mbedtls_x509_crt ca; // Parsed CA certificate
- mbedtls_x509_crt cert; // Parsed certificate
- mbedtls_pk_context pk; // Private key context
- mbedtls_ssl_context ssl; // SSL/TLS context
- mbedtls_ssl_config conf; // SSL/TLS config
- #ifdef MBEDTLS_SSL_SESSION_TICKETS
- mbedtls_ssl_ticket_context ticket; // Session tickets context
- #endif
- // https://github.com/Mbed-TLS/mbedtls/blob/3b3c652d/include/mbedtls/ssl.h#L5071C18-L5076C29
- unsigned char *throttled_buf; // see #3074
- size_t throttled_len;
- bool check_name; // set when hostname was set, but no CA certificate given
- };
- #endif
- #if MG_TLS == MG_TLS_OPENSSL || MG_TLS == MG_TLS_WOLFSSL
- #include <openssl/err.h>
- #include <openssl/ssl.h>
- #include <openssl/x509v3.h>
- struct mg_tls {
- BIO_METHOD *bm;
- SSL_CTX *ctx;
- SSL *ssl;
- char *name; // matching hostname
- bool check_name; // set when hostname was set, but no CA certificate given
- };
- #endif
- // WebSocket frame opcodes, used in mg_ws_send() op parameter and
- // in the low 4 bits of mg_ws_message.flags.
- #define WEBSOCKET_OP_CONTINUE 0 // Continuation frame (fragmented message)
- #define WEBSOCKET_OP_TEXT 1 // Text (UTF-8) data frame
- #define WEBSOCKET_OP_BINARY 2 // Binary data frame
- #define WEBSOCKET_OP_CLOSE 8 // Connection close control frame
- #define WEBSOCKET_OP_PING 9 // Ping control frame (auto-replied with PONG)
- #define WEBSOCKET_OP_PONG 10 // Pong control frame
- // WebSocket message delivered as ev_data in MG_EV_WS_MSG and MG_EV_WS_CTL.
- // data is a zero-copy slice into the receive buffer; valid until the next
- // mg_mgr_poll() call.
- struct mg_ws_message {
- struct mg_str data; // Message payload
- uint8_t flags; // First byte of the WS frame header: FIN (bit7) | opcode (bits3:0)
- };
- // Opens an outbound WebSocket connection.
- //
- // Returns:
- // Client connection, or NULL on error.
- // Example:
- // mg_ws_connect(&mgr, "ws://localhost:8000/websocket", fn, NULL, NULL);
- // Full examples:
- // tutorials/websocket/websocket-client, tutorials/mqtt/mqtt-over-ws-client
- // Related APIs:
- // mg_ws_send(), mg_ws_printf(), mg_tls_init(), mg_ws_upgrade()
- // Notes:
- // url may use ws:// or wss://. Sends the HTTP Upgrade request immediately.
- // fmt is a printf-style string for extra HTTP request headers; each header
- // must end with "\r\n". The user-supplied fn event handler receives
- // MG_EV_WS_OPEN on handshake success, MG_EV_WS_MSG for messages, and
- // MG_EV_WS_CTL for control frames.
- struct mg_connection *mg_ws_connect(struct mg_mgr *, const char *url,
- mg_event_handler_t fn, void *fn_data,
- const char *fmt, ...);
- // Upgrades a server-side HTTP connection to WebSocket.
- //
- // Example:
- // if (mg_match(hm->uri, mg_str("/websocket"), NULL)) {
- // mg_ws_upgrade(c, hm, NULL);
- // }
- // Full examples:
- // tutorials/websocket/websocket-server,
- // tutorials/websocket/json-rpc-over-websocket, tutorials/core/timers
- // Related APIs:
- // mg_http_listen(), mg_match(), mg_ws_send(), mg_ws_printf()
- // Notes:
- // Call from an MG_EV_HTTP_MSG handler and pass that event's hm. fmt is a
- // printf-style string for extra response headers; each header must end with
- // "\r\n". Fires MG_EV_WS_OPEN immediately on success. Sends HTTP 426 and
- // drains the connection if the request lacks Sec-WebSocket-Key.
- void mg_ws_upgrade(struct mg_connection *, struct mg_http_message *,
- const char *fmt, ...);
- // Sends one WebSocket frame.
- //
- // Returns:
- // Number of bytes appended to c->send; 0 if the frame header cannot be
- // appended.
- // Example:
- // mg_ws_send(c, "hello", 5, WEBSOCKET_OP_TEXT);
- // Full examples:
- // tutorials/websocket/websocket-server, tutorials/websocket/websocket-client,
- // tutorials/core/timers
- // Related APIs:
- // mg_ws_connect(), mg_ws_upgrade(), mg_ws_printf(), mg_ws_wrap()
- // Notes:
- // op is one of WEBSOCKET_OP_*. Client connections are automatically masked
- // per RFC 6455. On OOM, the return value can be smaller than header + len.
- // Data is appended to c->send and sent by a later mg_mgr_poll() call.
- size_t mg_ws_send(struct mg_connection *, const void *buf, size_t len, int op);
- // Wraps the last len bytes already in c->send with a WebSocket frame header
- // and opcode op. Used internally by mg_ws_printf(); call it directly when you
- // have written data into c->send manually and need to frame it.
- // Returns c->send.len (total buffer size after the operation).
- size_t mg_ws_wrap(struct mg_connection *, size_t len, int op);
- // Formats a WebSocket message using printf-style fmt and sends it with
- // opcode op (WEBSOCKET_OP_TEXT or WEBSOCKET_OP_BINARY).
- // Returns the number of payload bytes written, or 0 on OOM.
- size_t mg_ws_printf(struct mg_connection *c, int op, const char *fmt, ...);
- size_t mg_ws_vprintf(struct mg_connection *c, int op, const char *fmt,
- va_list *);
- // Time / SNTP functions
- // Return milliseconds since boot (uptime). Never goes backwards.
- // On RTOS targets (FreeRTOS, ThreadX, Zephyr, etc.) uses the RTOS tick count.
- // On STM32/Cube uses HAL_GetTick(). On Arduino uses millis().
- // On Linux/macOS uses CLOCK_MONOTONIC_RAW or CLOCK_MONOTONIC; falls back to
- // CLOCK_REALTIME if neither is available.
- uint64_t mg_millis(void);
- // Boot timestamp in ms since Epoch. 0 until the first successful SNTP sync;
- // updated automatically by mg_sntp_connect() on each successful response.
- extern uint64_t mg_boot_timestamp_ms;
- // Return milliseconds since Epoch: mg_millis() + mg_boot_timestamp_ms.
- // Until a successful SNTP request completes, this is identical to mg_millis().
- uint64_t mg_now(void);
- // Checks whether a periodic deadline has expired.
- //
- // Returns:
- // True when the timer has fired; false otherwise.
- // Example:
- // uint64_t timer = 0;
- // if (mg_timer_expired(&timer, 1000, mg_millis())) {
- // MG_INFO(("every second"));
- // }
- // Full examples:
- // tutorials/http/http-server/arduino/teensy41-http,
- // tutorials/mqtt/mqtt-client
- // Related APIs:
- // mg_millis(), mg_now()
- // Notes:
- // Initialise *expiration to 0 before first use. On expiry, this function
- // advances *expiration by period and handles time wrap-around.
- bool mg_timer_expired(uint64_t *expiration, uint64_t period, uint64_t now);
- // Connect to an SNTP server and send a time request.
- // `url` defaults to "udp://time.google.com:123" when NULL.
- // On success the internal boot timestamp is updated so that mg_now() returns
- // the correct wall-clock time, and MG_EV_SNTP_TIME is fired on `fn` (if not
- // NULL) with ev_data pointing to a uint64_t containing the epoch in milliseconds.
- // Pass fn == NULL and fn_data == NULL for a fire-and-forget sync that only
- // updates mg_boot_timestamp_ms. Typical polling usage:
- //
- // ```c
- // uint64_t timer = 0;
- // for (;;) {
- // uint64_t period = mg_boot_timestamp_ms == 0 ? 1000 : 3600 * 1000;
- // if (mg_timer_expired(&timer, period, mg_millis())) {
- // mg_sntp_connect(&mgr, NULL, NULL, NULL);
- // }
- // mg_mgr_poll(&mgr, 1000);
- // }
- // ```
- struct mg_connection *mg_sntp_connect(struct mg_mgr *mgr, const char *url,
- mg_event_handler_t fn, void *fn_data);
- // Private API, do not expose
- void mg_sntp_request(struct mg_connection *c);
- int64_t mg_sntp_parse(const unsigned char *buf, size_t len);
- // MQTT packet type codes. The received command is in mg_mqtt_message.cmd.
- #define MQTT_CMD_CONNECT 1
- #define MQTT_CMD_CONNACK 2
- #define MQTT_CMD_PUBLISH 3
- #define MQTT_CMD_PUBACK 4
- #define MQTT_CMD_PUBREC 5
- #define MQTT_CMD_PUBREL 6
- #define MQTT_CMD_PUBCOMP 7
- #define MQTT_CMD_SUBSCRIBE 8
- #define MQTT_CMD_SUBACK 9
- #define MQTT_CMD_UNSUBSCRIBE 10
- #define MQTT_CMD_UNSUBACK 11
- #define MQTT_CMD_PINGREQ 12
- #define MQTT_CMD_PINGRESP 13
- #define MQTT_CMD_DISCONNECT 14
- #define MQTT_CMD_AUTH 15
- // MQTT5 property IDs. Used in mg_mqtt_prop.id.
- #define MQTT_PROP_PAYLOAD_FORMAT_INDICATOR 0x01
- #define MQTT_PROP_MESSAGE_EXPIRY_INTERVAL 0x02
- #define MQTT_PROP_CONTENT_TYPE 0x03
- #define MQTT_PROP_RESPONSE_TOPIC 0x08
- #define MQTT_PROP_CORRELATION_DATA 0x09
- #define MQTT_PROP_SUBSCRIPTION_IDENTIFIER 0x0B
- #define MQTT_PROP_SESSION_EXPIRY_INTERVAL 0x11
- #define MQTT_PROP_ASSIGNED_CLIENT_IDENTIFIER 0x12
- #define MQTT_PROP_SERVER_KEEP_ALIVE 0x13
- #define MQTT_PROP_AUTHENTICATION_METHOD 0x15
- #define MQTT_PROP_AUTHENTICATION_DATA 0x16
- #define MQTT_PROP_REQUEST_PROBLEM_INFORMATION 0x17
- #define MQTT_PROP_WILL_DELAY_INTERVAL 0x18
- #define MQTT_PROP_REQUEST_RESPONSE_INFORMATION 0x19
- #define MQTT_PROP_RESPONSE_INFORMATION 0x1A
- #define MQTT_PROP_SERVER_REFERENCE 0x1C
- #define MQTT_PROP_REASON_STRING 0x1F
- #define MQTT_PROP_RECEIVE_MAXIMUM 0x21
- #define MQTT_PROP_TOPIC_ALIAS_MAXIMUM 0x22
- #define MQTT_PROP_TOPIC_ALIAS 0x23
- #define MQTT_PROP_MAXIMUM_QOS 0x24
- #define MQTT_PROP_RETAIN_AVAILABLE 0x25
- #define MQTT_PROP_USER_PROPERTY 0x26
- #define MQTT_PROP_MAXIMUM_PACKET_SIZE 0x27
- #define MQTT_PROP_WILDCARD_SUBSCRIPTION_AVAILABLE 0x28
- #define MQTT_PROP_SUBSCRIPTION_IDENTIFIER_AVAILABLE 0x29
- #define MQTT_PROP_SHARED_SUBSCRIPTION_AVAILABLE 0x2A
- // Property value types used internally to encode/decode MQTT5 properties.
- enum {
- MQTT_PROP_TYPE_BYTE,
- MQTT_PROP_TYPE_STRING,
- MQTT_PROP_TYPE_STRING_PAIR,
- MQTT_PROP_TYPE_BINARY_DATA,
- MQTT_PROP_TYPE_VARIABLE_INT,
- MQTT_PROP_TYPE_INT,
- MQTT_PROP_TYPE_SHORT
- };
- // Return codes from mg_mqtt_parse().
- enum { MQTT_OK, MQTT_INCOMPLETE, MQTT_MALFORMED };
- // A single MQTT5 property. Use in mg_mqtt_opts.props / mg_mqtt_opts.will_props
- // arrays, and iterate received properties with mg_mqtt_next_prop().
- struct mg_mqtt_prop {
- uint8_t id; // Property ID, one of MQTT_PROP_*
- uint32_t iv; // Integer value for BYTE, SHORT, INT, VARIABLE_INT types
- struct mg_str key; // Property key string; only set for USER_PROPERTY pairs
- struct mg_str val; // String/binary value; set for STRING, BINARY_DATA, and USER_PROPERTY
- };
- // Options passed to mg_mqtt_connect(), mg_mqtt_pub(), mg_mqtt_sub(),
- // mg_mqtt_unsub(), and mg_mqtt_disconnect(). Zero-initialise and set only
- // the fields relevant to the operation being called.
- struct mg_mqtt_opts {
- struct mg_str user; // CONNECT: username; empty = omit
- struct mg_str pass; // CONNECT: password; empty = omit
- struct mg_str client_id; // CONNECT: client ID; empty = auto-generate
- struct mg_str topic; // CONNECT: will topic; PUBLISH/SUBSCRIBE/UNSUBSCRIBE: topic
- struct mg_str message; // CONNECT: will payload; PUBLISH: message payload
- uint8_t qos; // QoS level: 0, 1, or 2
- uint8_t version; // MQTT version: 4 (3.1.1) or 5; 0 defaults to 4
- uint16_t keepalive; // CONNECT: keepalive interval in seconds; 0 = no timeout
- uint16_t retransmit_id; // PUBLISH: packet ID for retransmit; init to 0 for new message
- bool retain; // PUBLISH/CONNECT will: set the retain flag
- bool clean; // CONNECT: start a clean session
- struct mg_mqtt_prop *props; // MQTT5: properties array; NULL if none
- size_t num_props; // MQTT5: number of entries in props
- struct mg_mqtt_prop *will_props; // MQTT5 CONNECT: will properties; NULL if none
- size_t num_will_props; // MQTT5: number of entries in will_props
- };
- // Received MQTT message. Passed as ev_data for MG_EV_MQTT_MSG (PUBLISH),
- // MG_EV_MQTT_CMD (all packets), and MG_EV_MQTT_OPEN (CONNACK).
- // topic, data, and dgram are zero-copy slices into the receive buffer; they
- // are only valid until the next mg_mgr_poll() call.
- struct mg_mqtt_message {
- struct mg_str topic; // PUBLISH: message topic; slice into dgram
- struct mg_str data; // PUBLISH: message payload; slice into dgram
- struct mg_str dgram; // Complete raw MQTT packet, including fixed header
- uint16_t id; // Packet ID; set for QoS>0 PUBLISH, PUBACK, PUBREC, PUBREL, PUBCOMP, SUBACK, UNSUBACK
- uint8_t cmd; // Packet type, one of MQTT_CMD_*
- uint8_t qos; // QoS level extracted from the PUBLISH fixed header
- uint8_t ack; // CONNACK return code; 0 = success
- size_t props_start; // MQTT5: byte offset from dgram.buf to start of properties
- size_t props_size; // MQTT5: byte length of the properties section
- };
- // Opens an MQTT client connection and sends a CONNECT packet.
- //
- // Returns:
- // Client connection, or NULL on error.
- // Example:
- // struct mg_mqtt_opts opts = {.client_id = mg_str("device1")};
- // mg_mqtt_connect(&mgr, "mqtt://broker:1883", &opts, fn, NULL);
- // Full examples:
- // tutorials/mqtt/mqtt-client, tutorials/mqtt/mqtt-client-aws-iot,
- // tutorials/mqtt/ota-over-mqtt
- // Related APIs:
- // mg_mqtt_pub(), mg_mqtt_sub(), mg_tls_init(), mg_mgr_poll()
- // Notes:
- // opts may be NULL to use MQTT 3.1.1 defaults with no auth and an auto client
- // ID. The user-supplied fn event handler receives normal connection events,
- // MG_EV_MQTT_OPEN when CONNACK is received, MG_EV_MQTT_MSG for incoming
- // PUBLISH packets, and MG_EV_MQTT_CMD for every received MQTT packet.
- struct mg_connection *mg_mqtt_connect(struct mg_mgr *, const char *url,
- const struct mg_mqtt_opts *opts,
- mg_event_handler_t fn, void *fn_data);
- // Creates an MQTT server listener on url.
- // Fires MG_EV_MQTT_CMD for each complete packet received (ev_data: struct mg_mqtt_message *).
- // Returns NULL on error.
- struct mg_connection *mg_mqtt_listen(struct mg_mgr *mgr, const char *url,
- mg_event_handler_t fn, void *fn_data);
- // Sends a CONNECT packet on an already-open connection.
- // Called automatically by mg_mqtt_connect(); exposed for advanced use such
- // as re-authenticating on an existing connection.
- void mg_mqtt_login(struct mg_connection *c, const struct mg_mqtt_opts *opts);
- // Sends an MQTT PUBLISH packet.
- //
- // Returns:
- // 0 for QoS 0; assigned packet ID for QoS 1 or 2.
- // Example:
- // struct mg_mqtt_opts opts = {
- // .topic = mg_str("device/status"),
- // .message = mg_str("{\"ok\":true}"),
- // .qos = 1,
- // };
- // uint16_t id = mg_mqtt_pub(c, &opts);
- // Full examples:
- // tutorials/mqtt/mqtt-client, tutorials/mqtt/mqtt-client-aws-iot,
- // tutorials/mqtt/ota-over-mqtt
- // Related APIs:
- // mg_mqtt_connect(), mg_mqtt_sub(), mg_mqtt_send_header()
- // Notes:
- // On success, opts.topic and opts.message are copied into c->send before the
- // function returns. To retransmit a QoS message, set opts.retransmit_id to the
- // packet ID returned by the previous call; use 0 for a new message.
- uint16_t mg_mqtt_pub(struct mg_connection *c, const struct mg_mqtt_opts *opts);
- // Sends an MQTT SUBSCRIBE packet.
- //
- // Example:
- // struct mg_mqtt_opts opts = {.topic = mg_str("device/rx"), .qos = 1};
- // mg_mqtt_sub(c, &opts);
- // Full examples:
- // tutorials/mqtt/mqtt-client, tutorials/mqtt/mqtt-client-aws-iot,
- // tutorials/mqtt/ota-over-mqtt
- // Related APIs:
- // mg_mqtt_connect(), mg_mqtt_pub(), mg_mqtt_unsub()
- // Notes:
- // Send after MG_EV_MQTT_OPEN reports a successful CONNACK. Incoming PUBLISH
- // messages are delivered to the user-supplied fn event handler as
- // MG_EV_MQTT_MSG with ev_data pointing to struct mg_mqtt_message.
- void mg_mqtt_sub(struct mg_connection *, const struct mg_mqtt_opts *opts);
- // Sends an UNSUBSCRIBE packet for opts.topic.
- void mg_mqtt_unsub(struct mg_connection *c, const struct mg_mqtt_opts *opts);
- // Parses a raw MQTT packet in buf/len. version must be 4 (MQTT 3.1.1) or 5.
- // On success, fills *m; topic, data, and dgram slice into buf (zero-copy).
- // Returns MQTT_OK, MQTT_INCOMPLETE (need more data), or MQTT_MALFORMED.
- int mg_mqtt_parse(const uint8_t *, size_t, uint8_t, struct mg_mqtt_message *);
- // Low-level helper: sends the MQTT fixed header (command byte and
- // variable-length remaining-length field). Call before writing the PDU body.
- // cmd: MQTT_CMD_*; flags: low 4 bits of the first byte; len: remaining length.
- void mg_mqtt_send_header(struct mg_connection *, uint8_t cmd, uint8_t flags,
- uint32_t len);
- // Sends a PINGREQ packet.
- void mg_mqtt_ping(struct mg_connection *);
- // Sends a PINGRESP packet.
- void mg_mqtt_pong(struct mg_connection *);
- // Sends a DISCONNECT packet. For MQTT5, opts.props can carry reason
- // properties. opts may be NULL for a plain disconnect with no properties.
- void mg_mqtt_disconnect(struct mg_connection *, const struct mg_mqtt_opts *);
- // Iterates MQTT5 properties in a received message. Start with ofs=0; pass
- // the returned value back on each successive call. Returns 0 when done.
- // Fills *prop with each property; key and val are zero-copy slices into msg->dgram.
- size_t mg_mqtt_next_prop(struct mg_mqtt_message *, struct mg_mqtt_prop *,
- size_t ofs);
- // DNS record types, used in mg_dns_rr.atype and mg_mdns_query().
- #define MG_DNS_RTYPE_A 1 // IPv4 address (4 bytes)
- #define MG_DNS_RTYPE_PTR 12 // Domain name pointer, used for reverse lookups and service discovery
- #define MG_DNS_RTYPE_TXT 16 // Arbitrary text, used by DNS-SD for service metadata
- #define MG_DNS_RTYPE_AAAA 28 // IPv6 address (16 bytes)
- #define MG_DNS_RTYPE_SRV 33 // Service location: priority, weight, port, target hostname
- // Mongoose sends DNS queries that contain only one question:
- // either A (IPv4) or AAAA (IPv6) address lookup.
- // Therefore, we expect zero or one answer.
- // If `resolved` is true, then `addr` contains resolved IPv4 or IPV6 address.
- struct mg_dns_message {
- uint16_t txnid; // Transaction ID
- bool resolved; // Resolve successful, addr is set
- struct mg_addr addr; // Resolved address
- char name[256]; // Host name
- };
- // DNS wire-format header (RFC 1035). All fields are in network byte order;
- // use mg_ntohs() to read them.
- struct mg_dns_header {
- uint16_t txnid; // Transaction ID, matched between query and response
- uint16_t flags; // Flags: bit15=QR (0=query,1=response), bit10=AA, bit8=RD
- uint16_t num_questions; // Number of question records following the header
- uint16_t num_answers; // Number of answer records in the response
- uint16_t num_authority_prs; // Number of authority records
- uint16_t num_other_prs; // Number of additional records
- };
- // Parsed DNS resource record fields, extracted from the wire format.
- struct mg_dns_rr {
- uint16_t nlen; // Byte length of the encoded name in the wire format
- uint16_t atype; // Record type: MG_DNS_RTYPE_A=1, AAAA=28, PTR=12, SRV=33, TXT=16
- uint16_t aclass; // Record class: 1=INET; mDNS queries: bit15=QU (unicast request)
- uint16_t alen; // Byte length of the RDATA section (e.g. 4 for A, 16 for AAAA)
- };
- // DNS-SD service description. Used by the user to describe a service to advertise.
- struct mg_dnssd_record {
- struct mg_str srvcproto; // Service and protocol label, e.g. "_http._tcp"
- struct mg_str txt; // TXT record contents, verbatim
- uint16_t port; // Port number for the SRV record
- };
- // ev_data for MG_EV_MDNS_REQ. The handler must set is_resp=true and fill r
- // (and optionally respname/addr) to send a response; leave is_resp=false to ignore.
- struct mg_mdns_req {
- struct mg_dns_rr *rr; // Parsed resource record from the incoming query
- struct mg_dnssd_record *r; // User-supplied service record to include in the response
- struct mg_str reqname; // Queried hostname, without the .local suffix
- struct mg_str respname; // Hostname to use in response; defaults to fn_data if empty
- struct mg_addr *addr; // IP address for A record; uses local interface if NULL
- bool is_listing; // True if this is a service-discovery listing (_services._dns-sd._udp)
- bool is_resp; // Set to true in the handler to trigger a response
- bool is_unicast; // True if the client requested a unicast (QU) response
- };
- // ev_data for MG_EV_MDNS_RESP, carrying address/data from a mDNS response
- struct mg_mdns_resp {
- struct mg_dns_rr *rr; // Resource record from the response (1st in chain)
- struct mg_str name; // Resolved hostname, without the .local suffix
- struct mg_addr addr; // Resolved IP address
- struct mg_dnssd_record sd; // Service Discovery data
- };
- // Parses a DNS query or response from buf/len into dm. Returns true on success.
- // On a response, sets dm->resolved=true and fills dm->addr if an A/AAAA record
- // is found. Always fills dm->txnid and dm->name. Rejects packets larger than 512 bytes.
- bool mg_dns_parse(const uint8_t *buf, size_t len, struct mg_dns_message *dm);
- // Parses one DNS record at offset ofs in buf/len into rr. Set is_question=true
- // for question records (no RDATA), false for answer records. Returns the number
- // of bytes consumed (use to advance ofs), or 0 on error.
- size_t mg_dns_parse_rr(const uint8_t *buf, size_t len, size_t ofs,
- bool is_question, struct mg_dns_rr *rr);
- // Creates an mDNS listener on UDP multicast 224.0.0.251:5353. Registers it as
- // the manager's mDNS resolver (mgr->mdns). Fires MG_EV_MDNS_REQ for incoming
- // queries and MG_EV_MDNS_RESP for incoming responses. Returns NULL on error.
- // fn_data is a NUL-terminated server name, or NULL to pass all requests to fn.
- struct mg_connection *mg_mdns_listen(struct mg_mgr *mgr, mg_event_handler_t fn,
- void *fn_data);
- // Sends an mDNS query on connection c (from mg_mdns_listen()) for name, with
- // record type rtype (e.g. MG_DNS_RTYPE_A). Returns false on send error.
- bool mg_mdns_query(struct mg_connection *c, const char *name, unsigned int rtype);
- // Private API, do not expose or call in the user app
- void mg_resolve(struct mg_connection *, const char *url);
- void mg_resolve_cancel(struct mg_connection *);
- // Modbus TCP function codes passed in mg_modbus_req.func.
- #define MG_MODBUS_FUNC_READ_COILS 1 // Read 1-2000 discrete output coils
- #define MG_MODBUS_FUNC_READ_DISCRETE_INPUTS 2 // Read 1-2000 discrete input coils
- #define MG_MODBUS_FUNC_READ_HOLDING_REGISTERS 3 // Read 1-125 holding registers
- #define MG_MODBUS_FUNC_READ_INPUT_REGISTERS 4 // Read 1-125 input registers
- #define MG_MODBUS_FUNC_WRITE_SINGLE_COIL 5 // Write one output coil
- #define MG_MODBUS_FUNC_WRITE_SINGLE_REGISTER 6 // Write one holding register
- #define MG_MODBUS_FUNC_WRITE_MULTIPLE_COILS 15 // Write 1-1968 output coils
- #define MG_MODBUS_FUNC_WRITE_MULTIPLE_REGISTERS 16 // Write 1-123 holding registers
- // Standard Modbus exception codes. Set mg_modbus_req.error to one of these
- // in the MG_EV_MODBUS_REQ handler to return an exception response to the client.
- #define MG_MODBUS_ERR_NONE 0 // No error; send a normal response
- #define MG_MODBUS_ERR_ILLEGAL_FUNCTION 1 // Function code not supported
- #define MG_MODBUS_ERR_ILLEGAL_ADDRESS 2 // Starting address or range out of bounds
- #define MG_MODBUS_ERR_ILLEGAL_VALUE 3 // Data value not accepted
- #define MG_MODBUS_ERR_DEVICE_FAILURE 4 // Unrecoverable device error
- // Modbus request passed as ev_data to the MG_EV_MODBUS_REQ event handler.
- //
- // For READ functions (READ_COILS, READ_DISCRETE_INPUTS, READ_HOLDING_REGISTERS,
- // READ_INPUT_REGISTERS): u.bits / u.regs points to a zeroed, heap-allocated
- // array of len entries. The handler fills in the values to return.
- //
- // For WRITE functions: u.bits / u.regs is pre-populated from the client
- // request. len=1 for single-write functions.
- //
- // Do NOT free u.bits or u.regs - the library frees them after the handler
- // returns and the response has been sent.
- //
- // Set error to a non-zero MG_MODBUS_ERR_* code to send an exception response
- // instead of a data response. The response is sent automatically on return.
- struct mg_modbus_req {
- uint8_t func; // Function code, one of MG_MODBUS_FUNC_*
- uint8_t error; // Exception code; set to MG_MODBUS_ERR_* to return an error
- uint16_t addr; // Starting coil/register address from the request
- union {
- bool *bits; // Coil values; used by coil function codes
- uint16_t *regs; // Register values; used by register function codes
- } u;
- uint16_t len; // Number of entries in u.bits or u.regs
- };
- // Creates a Modbus TCP listener on url. Fires MG_EV_MODBUS_REQ for each
- // complete request; ev_data is struct mg_modbus_req *. Returns the listening
- // connection, or NULL on error.
- struct mg_connection *mg_modbus_listen(struct mg_mgr *mgr, const char *url,
- mg_event_handler_t fn, void *fn_data);
- // Maximum JSON nesting depth. mg_json_get() returns MG_JSON_TOO_DEEP if
- // the path traverses more than this many nested objects/arrays.
- #ifndef MG_JSON_MAX_DEPTH
- #define MG_JSON_MAX_DEPTH 30
- #endif
- // Error codes returned by mg_json_get(). Successful returns are >= 0.
- enum { MG_JSON_TOO_DEEP = -1, MG_JSON_INVALID = -2, MG_JSON_NOT_FOUND = -3 };
- // Low-level token locator. Finds the JSON token at path inside json and
- // returns its byte offset in json.buf. Sets *toklen to the token length.
- // toklen may be NULL if only a presence check is needed.
- // path must start with "$" (root). Use ".key" for object fields and "[N]"
- // for array indices. Example: "$.items[0].name"
- // Returns MG_JSON_NOT_FOUND, MG_JSON_INVALID, or MG_JSON_TOO_DEEP on error.
- int mg_json_get(struct mg_str json, const char *path, int *toklen);
- // Returns the raw JSON token at path.
- //
- // Returns:
- // Zero-copy mg_str slice into json.buf, or {NULL, 0} if not found or invalid.
- // Example:
- // struct mg_str tok = mg_json_get_tok(body, "$.device.name");
- // Full examples:
- // src/dash.c
- // Related APIs:
- // mg_json_get(), mg_json_get_str(), mg_json_unescape()
- // Notes:
- // The returned token is not NUL-terminated. String tokens include the
- // surrounding double quotes and escape sequences; use mg_json_unescape() or
- // mg_json_get_str() when you need decoded string content.
- struct mg_str mg_json_get_tok(struct mg_str json, const char *path);
- // Parses a numeric JSON value at path into *v.
- // Returns true and sets *v on success. Returns false if not found or not a
- // number. v may be NULL to check existence only.
- bool mg_json_get_num(struct mg_str json, const char *path, double *v);
- // Parses a boolean JSON value at path into *v.
- // Returns true and sets *v on success. Returns false if not found or not a
- // boolean literal. v may be NULL to check existence only.
- bool mg_json_get_bool(struct mg_str json, const char *path, bool *v);
- // Returns a JSON number at path as a long, or dflt if not found or not a
- // number. Use mg_json_get_num() when you need to distinguish missing from 0.
- long mg_json_get_long(struct mg_str json, const char *path, long dflt);
- // Returns a heap-allocated, NUL-terminated, JSON-unescaped copy of the string
- // at path. Caller must mg_free() the result. Returns NULL if not found or the
- // token is not a JSON string.
- char *mg_json_get_str(struct mg_str json, const char *path);
- // Decodes a hex-encoded JSON string at path into a heap-allocated byte array.
- // Sets *len to the decoded byte count. Caller must mg_free() the result.
- // Returns NULL if not found, not a string, or not valid hexadecimal.
- char *mg_json_get_hex(struct mg_str json, const char *path, int *len);
- // Decodes a base64-encoded JSON string at path into a heap-allocated byte
- // array. Sets *len to the decoded byte count. Caller must mg_free() the result.
- // Returns NULL if not found or not a string.
- char *mg_json_get_b64(struct mg_str json, const char *path, int *len);
- // Writes a JSON-unescaped string value at path into a caller-supplied buffer.
- //
- // Returns:
- // Number of bytes written excluding the NUL, or 0 on error, not found,
- // non-string token, too-small buffer, or an empty string.
- // Example:
- // char name[32];
- // mg_json_unescape(body, "$.device.name", name, sizeof(name));
- // Full examples:
- // src/dash.c, src/ota.c
- // Related APIs:
- // mg_json_get_tok(), mg_json_get_str(), mg_json_get_num()
- // Notes:
- // On success, NUL-terminates when n > 0. The destination buffer is owned by
- // the caller. Only string tokens are unescaped; other token types return 0.
- size_t mg_json_unescape(struct mg_str json, const char *path, char *, size_t);
- // Sequential iterator over a JSON object or array. Start with ofs=0.
- // Each call fills *key and *val with the next entry and returns the new ofs
- // to pass on the next call. Returns 0 when there are no more entries.
- // For arrays, *key is set to {NULL, 0}. For objects, *key is the raw
- // quoted key (e.g. "\"name\""). *val is the raw unparsed token.
- size_t mg_json_next(struct mg_str obj, size_t ofs, struct mg_str *key,
- struct mg_str *val);
- struct mg_jwt_opts {
- struct mg_str claims; // JSON payload
- struct mg_str header; // Extra header members, no braces; alg/typ are set
- struct mg_str kid; // Key ID protected header
- struct mg_str secret; // HS256 secret
- const uint8_t *private_key; // ES256 private key (MG_TLS_BUILTIN only)
- const uint8_t *public_key; // ES256 public key (MG_TLS_BUILTIN only)
- };
- // Signs JSON claims as a compact JWT. Returns JWT length, or 0 on error.
- size_t mg_jwt_sign_hs256(const struct mg_jwt_opts *opts, char *buf,
- size_t len);
- // Verifies JWT and decodes JSON claims into buf. Returns claims length, or 0.
- size_t mg_jwt_verify_hs256(struct mg_str jwt, const struct mg_jwt_opts *opts,
- char *buf, size_t len);
- size_t mg_jwt_sign_es256(const struct mg_jwt_opts *opts, char *buf,
- size_t len);
- size_t mg_jwt_verify_es256(struct mg_str jwt, const struct mg_jwt_opts *opts,
- char *buf, size_t len);
- // In-flight JSON-RPC request. Populate and pass to mg_rpc_process() to
- // dispatch, or receive one pre-filled in a handler registered with mg_rpc_add().
- struct mg_rpc_req {
- struct mg_rpc **head; // Head of the handler list; allows handlers to call other RPCs
- struct mg_rpc *rpc; // Handler that matched this request; set by mg_rpc_process()
- mg_pfn_t pfn; // Output function for the response (e.g. mg_pfn_iobuf)
- void *pfn_data; // Argument passed to pfn (e.g. pointer to an mg_iobuf)
- void *req_data; // Arbitrary caller data, not touched by the RPC layer
- struct mg_str frame; // Raw JSON-RPC frame, e.g. {"id":1,"method":"add","params":[1,2]}
- };
- // A registered JSON-RPC method handler. Managed by mg_rpc_add/del; do not
- // allocate directly. method is a glob pattern matched via mg_match().
- struct mg_rpc {
- struct mg_rpc *next; // Next handler in the linked list
- struct mg_str method; // Method name glob pattern (heap-allocated copy)
- void (*fn)(struct mg_rpc_req *); // Handler function called on a match
- void *fn_data; // Passed to fn as r->rpc->fn_data
- };
- // Allocates a handler entry and prepends it to *head. method_pattern is
- // copied (mg_strdup). Glob patterns are supported, e.g. "get/*".
- // To receive JSON-RPC responses ($.result / $.error), register with method=""
- void mg_rpc_add(struct mg_rpc **head, struct mg_str method_pattern,
- void (*handler)(struct mg_rpc_req *), void *handler_data);
- // Removes and frees all handlers in *head whose fn matches handler.
- // Pass handler=NULL to remove every handler in the list.
- void mg_rpc_del(struct mg_rpc **head, void (*handler)(struct mg_rpc_req *));
- // Dispatches r->frame to the matching handler. Looks up "$.method" and calls
- // the first handler whose pattern matches. If "$.result" or "$.error" is found
- // instead (i.e. r->frame is a JSON-RPC response), dispatches to the "" handler.
- // Sends a -32601 "not found" error if no handler matches, or -32700 on parse failure.
- void mg_rpc_process(struct mg_rpc_req *);
- // Sends a JSON-RPC success response: {"id":<id>,"result":<fmt>}.
- // fmt is a printf-style format string written to r->pfn; NULL sends "null".
- // Does nothing if the request frame has no "id" field (notification).
- void mg_rpc_ok(struct mg_rpc_req *, const char *fmt, ...);
- void mg_rpc_vok(struct mg_rpc_req *, const char *fmt, va_list *ap);
- // Sends a JSON-RPC error response: {"id":<id>,"error":{"code":<code>,"message":<fmt>}}.
- // fmt is a printf-style format string; NULL sends "null" as the message.
- // The "id" field is omitted if the request had none; the error is always sent.
- void mg_rpc_err(struct mg_rpc_req *, int code, const char *fmt, ...);
- void mg_rpc_verr(struct mg_rpc_req *, int code, const char *fmt, va_list *);
- // Built-in handler: responds with a JSON array of all registered method names.
- // Register it as a method handler, e.g. mg_rpc_add(&head, mg_str("rpc.list"), mg_rpc_list, NULL);
- void mg_rpc_list(struct mg_rpc_req *r);
- #ifndef MG_DASH_MAX_USER_NAME
- #define MG_DASH_MAX_USER_NAME 32
- #endif
- #ifndef MG_HTTP_ADDR
- #if MG_ARCH == MG_ARCH_UNIX || MG_ARCH == MG_ARCH_WIN32
- #define MG_HTTP_ADDR "http://0.0.0.0:8000"
- #define MG_HTTPS_ADDR "https://0.0.0.0:8443"
- #define MG_MODBUS_ADDR "tcp://0.0.0.0:8502"
- #else
- #define MG_HTTP_ADDR "http://0.0.0.0:80"
- #define MG_HTTPS_ADDR "http://0.0.0.0:443"
- #define MG_MODBUS_ADDR "tcp://0.0.0.0:502"
- #endif
- #endif
- #ifndef MG_DASH_MAX_SEND_BUF_SIZE
- #define MG_DASH_MAX_SEND_BUF_SIZE (MG_IO_SIZE * 5)
- #endif
- // C type of a value bound to a dashboard field, see struct mg_field
- enum mg_val_type {
- MG_VAL_INT, // int
- MG_VAL_UINT64, // uint64_t
- MG_VAL_BOOL, // bool
- MG_VAL_DBL, // double
- MG_VAL_STR, // Zero-terminated string
- MG_VAL_RAW, // Pre-formatted JSON value, copied verbatim
- };
- // Dashboard field: binds a JSON key to a C variable for read and/or write
- struct mg_field {
- const char *name; // JSON key
- enum mg_val_type type; // C type of the value, see enum mg_val_type
- void *value; // Pointer to the bound variable
- size_t value_size; // sizeof(*value) for type checking; 0 makes it read-only
- };
- // Operation passed to a struct mg_field_set read/write/delete/add callback.
- // MG_DASH_ADD: fields hold the values of a new element to append; *index is
- // not set. Return true to accept and persist it, false to reject (e.g. a cap
- // was reached)
- enum mg_dash_op { MG_DASH_READ, MG_DASH_WRITE, MG_DASH_DELETE, MG_DASH_ADD };
- struct mg_dash;
- // Authenticated (or guest) dashboard user
- struct mg_dash_user {
- struct mg_dash_user *next; // Next user in the list
- char name[MG_DASH_MAX_USER_NAME]; // Username
- char token[21]; // Session token, sent to the client as a cookie
- int level; // Access level, see struct mg_dash::authenticate
- uint64_t expire; // Session expiration time, see mg_millis()
- struct mg_dash *dash; // Dashboard this user belongs to
- };
- // Named group of related dashboard fields, e.g. "settings" or "metrics"
- struct mg_field_set {
- const char *name; // Set name, used as a JSON key
- struct mg_field *fields; // Zero-terminated array of fields
- bool (*fn)(enum mg_dash_op op,
- struct mg_dash_user *u); // Read/write/delete/add callback
- int *index; // Non-NULL: array set. *index is set before fn(READ) call;
- // fn sets *index = -1 to signal end of iteration.
- // Size query: framework sets *index = -1 before fn(READ); fn
- // sets *index = total size
- bool (*get_dir)(const struct mg_dash_user *u, char *buf,
- size_t len); // Non-NULL: file array
- struct mg_field_set *next; // Next set in the list
- };
- // Custom URI handler, registered with MG_DASH_REGISTER_CUSTOM_HANDLER()
- struct mg_dash_custom_handler {
- struct mg_dash_custom_handler *next; // Next handler in the list
- struct mg_str uri_pattern; // URI to match, see mg_match()
- mg_event_handler_t handler; // Event handler function
- void *handler_data; // Opaque data for the handler
- };
- // Dashboard instance: fields, users and handlers served over HTTP and WS
- struct mg_dash {
- struct mg_field_set *sets; // Field sets, see MG_DASH_ADD_FIELD_SET()
- struct mg_dash_custom_handler *custom_handlers; // Custom URI handlers
- // Validates pass, fills in user, returns access level (<= 0: failure).
- // NULL: no login required, all clients get guest access
- int (*authenticate)(char *user, size_t userlen, const char *pass);
- int session_auto_expiration_seconds; // Session lifetime, 0: 1 hour default
- struct mg_dash_user *guest; // Used when authenticate == NULL
- struct mg_fs *upload_fs; // FS for uploads/listing, default &mg_fs_posix
- };
- #define MG_DASH_ADD_FIELD_SET(dash_, set_) \
- do { \
- (set_)->next = (dash_)->sets; \
- (dash_)->sets = (set_); \
- } while (0)
- #define MG_DASH_REGISTER_CUSTOM_HANDLER(dash_, uri_, fn_, data_) \
- do { \
- static struct mg_dash_custom_handler ch_; \
- ch_.next = (dash_)->custom_handlers; \
- ch_.uri_pattern = mg_str(uri_); \
- ch_.handler = (fn_); \
- ch_.handler_data = (data_); \
- (dash_)->custom_handlers = &ch_; \
- } while (0)
- // Dashboard event handler. Pass to mg_http_listen() as the fn argument
- void mg_dash_ev_handler(struct mg_connection *c, int ev, void *ev_data);
- // Notify WebSocket clients that a field set changed: broadcasts the new
- // array size if *set->index < 0, or a single element update otherwise
- void mg_dash_send_change(struct mg_mgr *mgr, struct mg_field_set *);
- // Default reader for file-backed array sets (set->get_dir != NULL)
- // Usage example - this is a complete implemenation of the file manager:
- // ```c
- // static struct file {
- // int index;
- // char name[64];
- // size_t size;
- // uint64_t checksum;
- // } s_file;
- // static struct mg_field_set set_files;
- //
- // static bool get_dir(const struct mg_dash_user *u, char *buf, size_t len) {
- // (void) u;
- // mkdir("/tmp/dashboard", 0755);
- // mg_snprintf(buf, len, "%s", "/tmp/dashboard");
- // return true;
- // }
- //
- // static struct mg_field fields_files[] = {
- // {"name", MG_VAL_STR, s_file.name, sizeof(s_file.name)},
- // {"size", MG_VAL_UINT64, &s_file.size, 0},
- // {"checksum", MG_VAL_UINT64, &s_file.checksum, sizeof(s_file.checksum)},
- // {NULL, MG_VAL_INT, NULL, 0},
- // };
- //
- // static bool files_fn(enum mg_dash_op op, struct mg_dash_user *u) {
- // if (op == MG_DASH_WRITE) return s_uploads_enabled && u->level >= 7;
- // if (op != MG_DASH_READ) return false;
- // if (!mg_dash_dir_read(&set_files, u)) return false;
- // s_file.checksum = 0; // Mock to show how to set custom fields
- // return true;
- // }
- //
- // static struct mg_field_set set_files = {"files", fields_files, files_fn, &s_file.index, get_dir, NULL};
- // ```
- bool mg_dash_dir_read(struct mg_field_set *set, struct mg_dash_user *u);
- // Helper forward declarations for Mongoose CMSIS pack modules
- extern struct mg_mgr g_mgr;
- extern void mg_dash_init(struct mg_mgr *);
- extern void mg_dash_poll(struct mg_mgr *);
- extern void mg_mqtt_init(struct mg_mgr *);
- extern void mg_mqtt_poll(struct mg_mgr *);
- // Firmware OTA updates
- //
- // This is a low-level OTA API, not intended to be called directly by users.
- // Users are provided with a higher-level API:
- // - defining MG_OTA_URL enables HTTP or HTTPS pull-based updates
- // - mg_http_start_ota() enables push-based updates
- //
- // However, it is possible to use the mg_ota_* API directly. Below is the
- // example code of a function that is called repeatedly. It expects the
- // last chink of size 0, which marks the end of the OTA process
- //
- // ```c
- // static void ota(size_t total, size_t offset, void *buf, size_t len) {
- // bool ok = false;
- // if (ofs == 0 && (ok = mg_ota_begin(total)) == false) {
- // mg_ota_end();
- // } else if (len > 0 && (ok = mg_ota_write(buf, len)) == false) {
- // mg_ota_end();
- // } else if (len == 0) {}
- // ok = mg_ota_end();
- // }
- // return ok;
- // }
- // ```
- // Supported OTA targets
- #define MG_OTA_NONE 0 // No OTA support
- #define MG_OTA_STM32H5 1 // STM32 H5
- #define MG_OTA_STM32H7 2 // STM32 H7
- #define MG_OTA_STM32H7_DUAL_CORE 3 // STM32 H7 dual core
- #define MG_OTA_STM32F 4 // STM32 F7/F4/F2
- #define MG_OTA_CH32V307 100 // WCH CH32V307
- #define MG_OTA_U2A 200 // Renesas U2A16, U2A8, U2A6
- #define MG_OTA_RT1020 300 // IMXRT1020
- #define MG_OTA_RT1050 301 // IMXRT1050
- #define MG_OTA_RT1060 302 // IMXRT1060
- #define MG_OTA_RT1064 303 // IMXRT1064
- #define MG_OTA_RT1170 304 // IMXRT1170
- #define MG_OTA_MCXN 310 // MCXN947
- #define MG_OTA_RW612 320 // FRDM-RW612
- #define MG_OTA_FLASH 900 // OTA via internal flash
- #define MG_OTA_ESP32 910 // ESP32 OTA implementation
- #define MG_OTA_PICOSDK 920 // RP2040/2350 using Pico-SDK hardware_flash
- #define MG_OTA_CUSTOM 1000 // Custom implementation
- // OTA target. Settable in mongoose_config.h
- #ifndef MG_OTA
- #define MG_OTA MG_OTA_NONE
- #else
- #ifndef MG_IRAM
- #if defined(__GNUC__)
- // Places code block in .iram ELF section. A linker script can place it in RAM
- #define MG_IRAM __attribute__((noinline, section(".iram")))
- #else
- #define MG_IRAM
- #endif // compiler
- #endif // IRAM
- #endif // OTA
- // Starts the OTA process. Called once at the beginning of a firmware update.
- bool mg_ota_begin(size_t new_firmware_size);
- // Writes the next firmware chunk. Called repeatedly until all data is written.
- bool mg_ota_write(const void *buf, size_t len);
- // Ends the OTA process and commits the written firmware.
- bool mg_ota_end(void);
- // MG_OTA_ROLLBACK: swap firmware banks and reset. On flash-based OTA, the
- // default calls swap_fn() (no-op on single-bank) then resets. Override in
- // mongoose_config.h for platforms without mg_flash (ESP32, PicoSDK, etc.).
- #ifndef MG_OTA_ROLLBACK
- #define MG_OTA_ROLLBACK() \
- do { \
- mg_flash->swap_fn(); \
- NVIC_SystemReset(); \
- } while (0)
- #endif
- // Arm a hardware watchdog. mg_ota_poll() feeds it while in MG_OTA_TESTING state;
- // if the event loop hangs, it fires, resets the device, and MG_OTA_FAILED
- // triggers MG_OTA_ROLLBACK() on next boot. Timeout is arch-defined.
- #ifndef MG_OTA_ROLLBACK_TIMER_START
- #define MG_OTA_ROLLBACK_TIMER_START()
- #endif
- #ifndef MG_OTA_ROLLBACK_TIMER_FEED
- #define MG_OTA_ROLLBACK_TIMER_FEED()
- #endif
- // OTA state values for MG_OTA_STATE_GET / MG_OTA_STATE_SET.
- // MG_OTA_CONFIRMED: firmware is committed, normal operation.
- // MG_OTA_TESTING: new firmware booted for the first time; IWDG is armed.
- // If the device reboots while in this state, it transitions
- // to MG_OTA_FAILED and rolls back on the next boot.
- // MG_OTA_FAILED: previous boot did not commit in time; rollback on next boot.
- // MG_OTA_ROLLEDBACK: device rolled back to previous firmware. Sent to the OTA
- // server as boot=3 on every poll until a new OTA succeeds,
- // which overwrites this state with MG_OTA_TESTING.
- enum {
- MG_OTA_CONFIRMED = 0,
- MG_OTA_TESTING = 1,
- MG_OTA_FAILED = 2,
- MG_OTA_ROLLEDBACK = 3
- };
- // Persistent OTA state storage. Override in mongoose_config.h to persist state across resets.
- #ifndef MG_OTA_STATE_GET
- #define MG_OTA_STATE_GET() 0
- #endif
- #ifndef MG_OTA_STATE_SET
- #define MG_OTA_STATE_SET(val) (void) (val)
- #endif
- // Evaluation window for new firmware in seconds. mg_ota_poll() feeds the
- // rollback watchdog while in MG_OTA_TESTING state and within this window;
- // when it expires, auto-commits if the OTA server confirmed the same version,
- // otherwise stops feeding and the watchdog triggers a rollback.
- #ifndef MG_OTA_ROLLBACK_TIMEOUT_SECONDS
- #define MG_OTA_ROLLBACK_TIMEOUT_SECONDS 120
- #endif
- // Call once at boot, after clock and backup-domain init (e.g. after HAL_Init()
- // + SystemClock_Config() on CubeMX projects, or after hal_clock_init() on
- // Mongoose tutorials). The backup domain must be write-accessible so the state
- // transition TESTING → FAILED persists across resets.
- // Arms the rollback watchdog if new firmware is in TESTING state, rolls back
- // immediately if FAILED. mg_ota_poll() feeds the watchdog and auto-commits
- // when the server confirms the same version within the window.
- // boot (TESTING) → set FAILED → arm IWDG → run firmware
- // ├── server ok + window expires → set CONFIRMED → IWDG resets cleanly
- // └── no server ok + window expires → stop feeding → IWDG fires → FAILED → rollback
- #define MG_OTA_BOOT_CHECK() \
- do { \
- if (MG_OTA_STATE_GET() == MG_OTA_FAILED) { \
- MG_OTA_STATE_SET(MG_OTA_ROLLEDBACK); \
- MG_INFO(("Commit deadline expired, rolling back")); \
- MG_OTA_ROLLBACK(); \
- } else if (MG_OTA_STATE_GET() == MG_OTA_TESTING) { \
- MG_OTA_STATE_SET(MG_OTA_FAILED); \
- MG_INFO(("New firmware: commit within %u sec or rolls back", \
- (unsigned) MG_OTA_ROLLBACK_TIMEOUT_SECONDS)); \
- MG_OTA_ROLLBACK_TIMER_START(); \
- } \
- } while (0)
- // Pull-based OTA over HTTP or HTTPS. If it's HTTPS, MG_OTA_TLS_CA
- // needs to be defined. Fetches metadata_url, which must
- // return a JSON object like:
- // { "version": "1.2.3", "url": "FIRMWARE_URL", "size": 324645 }
- // If the server version differs from MG_OTA_FIRMWARE_VERSION, downloads
- // FIRMWARE_URL and performs the OTA update. fn is called on every outcome:
- // NULL on successful flash, "Same version" when already up to date, or an
- // error string on failure. Pass NULL to use the default handler which logs
- // failures via MG_ERROR.
- void mg_ota_url_check(struct mg_mgr *mgr, const char *metadata_url,
- void (*fn)(const char *error_message));
- // Firmware info URL for mg_ota_poll() which calls mg_ota_url_check().
- // Example: "http://mongoose.ws/ota/u/0/ota.json". See http://mongoose.ws/ota/
- // Settable in mongoose_config.h
- #ifndef MG_OTA_URL
- #define MG_OTA_URL NULL
- #endif
- // PEM or DER CA certificate used to authenticate an HTTPS OTA server. Set to
- // NULL to use HTTP. Set in mongoose_config.h.
- #ifndef MG_OTA_TLS_CA
- #define MG_OTA_TLS_CA NULL
- #endif
- // OTA status callback function for mg_ota_poll()
- #ifndef MG_OTA_STATUS_FN
- #define MG_OTA_STATUS_FN NULL
- #endif
- // Firmware version for mg_ota_poll(). Settable in mongoose_config.h
- #ifndef MG_OTA_FIRMWARE_VERSION
- #define MG_OTA_FIRMWARE_VERSION "1.0.0"
- #endif
- // Maximum version string length
- #ifndef MG_OTA_MAX_VERSION_LEN
- #define MG_OTA_MAX_VERSION_LEN 64
- #endif
- // How often mg_ota_poll() checks for a firmware update, in seconds
- #ifndef MG_OTA_PULL_INTERVAL_SECONDS
- #define MG_OTA_PULL_INTERVAL_SECONDS 60
- #endif
- // Set to 1 to define a custom mg_ota_device_id(). Settable in mongoose_config.h
- #ifndef MG_ENABLE_CUSTOM_DEVICE_ID
- #define MG_ENABLE_CUSTOM_DEVICE_ID 0
- #endif
- // Populates buf with a unique device ID string.
- // E.g. on STM32, uses the 96-bit MCU UID converted to a hex string.
- void mg_ota_device_id(char *buf, size_t len);
- // Checks for a firmware update over HTTP or HTTPS. Called automatically by
- // mg_mgr_poll() when MG_OTA_URL is set in mongoose_config.h. Do not call
- // directly.
- void mg_ota_poll(struct mg_mgr *);
- #if (MG_OTA != MG_OTA_NONE && MG_OTA != MG_OTA_CUSTOM) || MG_ENABLE_LFS
- struct mg_flash {
- void *start; // Address at which flash starts
- size_t size; // Flash size
- size_t secsz; // Sector size
- size_t align; // Write alignment
- bool (*write_fn)(void *, const void *, size_t); // Write function
- bool (*swap_fn)(void); // Swap partitions
- };
- extern struct mg_flash *mg_flash;
- bool mg_lfs_init(size_t size);
- bool mg_ota_flash_begin(size_t new_firmware_size, struct mg_flash *flash);
- bool mg_ota_flash_write(const void *buf, size_t len, struct mg_flash *flash);
- bool mg_ota_flash_end(struct mg_flash *flash);
- #endif
- struct mg_wifi_data {
- char *ssid, *pass; // STA mode, SSID to connect to
- char *apssid, *appass; // AP mode, our SSID
- uint32_t apip, apmask; // AP mode, our IP address and mask
- uint8_t security; // STA mode, TBD
- uint8_t apsecurity; // AP mode, TBD
- uint8_t apchannel; // AP mode, channel to use
- bool apmode; // start in AP mode; 'false' -> connect to 'ssid' != NULL
- };
- struct mg_wifi_scan_bss_data {
- struct mg_str SSID;
- char *BSSID;
- int16_t RSSI;
- uint8_t security;
- #define MG_WIFI_SECURITY_OPEN 0
- #define MG_WIFI_SECURITY_WEP MG_BIT(0)
- #define MG_WIFI_SECURITY_WPA MG_BIT(1)
- #define MG_WIFI_SECURITY_WPA2 MG_BIT(2)
- #define MG_WIFI_SECURITY_WPA3 MG_BIT(3)
- #define MG_WIFI_SECURITY_WPA_ENTERPRISE MG_BIT(4)
- #define MG_WIFI_SECURITY_WPA2_ENTERPRISE MG_BIT(5)
- #define MG_WIFI_SECURITY_WPA3_ENTERPRISE MG_BIT(6)
- uint8_t channel;
- unsigned band : 2;
- #define MG_WIFI_BAND_2G 0
- #define MG_WIFI_BAND_5G 1
- unsigned has_n : 1;
- unsigned has_ac : 1;
- unsigned has_ax : 1;
- };
- bool mg_wifi_scan(void);
- bool mg_wifi_connect(struct mg_wifi_data *);
- bool mg_wifi_disconnect(void);
- bool mg_wifi_ap_start(struct mg_wifi_data *);
- bool mg_wifi_ap_stop(void);
- #if MG_ENABLE_TCPIP
- // no config defaults to 0 => Ethernet
- enum mg_l2type { MG_TCPIP_L2_ETH = 0, MG_TCPIP_L2_PPP, MG_TCPIP_L2_PPPoE, MG_TCPIP_L2_USER };
- #if defined(__DCC__)
- #pragma pack(1)
- #else
- #pragma pack(push, 1)
- #endif
- struct mg_l2addr {
- union {
- uint8_t mac[6]; // ieee48
- uint64_t ieee64; // PPP ifcid
- uint16_t ieee16;
- } addr;
- };
- // L2 using L2 (PPPoE) must inherit the lower layer first, so they overlap
- struct eth_data {
- uint16_t vlan_id;
- };
- struct pppoe_data { // (struct eth_data *) &pppoe_data = pppoedata.eth
- struct eth_data eth;
- };
- union mg_l2data {
- struct eth_data eth;
- struct pppoe_data pppoe;
- };
- #if defined(__DCC__)
- #pragma pack(0)
- #else
- #pragma pack(pop)
- #endif
- enum mg_l2proto {
- MG_TCPIP_L2PROTO_IPV4 = 0,
- MG_TCPIP_L2PROTO_IPV6,
- MG_TCPIP_L2PROTO_ARP,
- MG_TCPIP_L2PROTO_PPPoE_DISC,
- MG_TCPIP_L2PROTO_PPPoE_SESS
- };
- enum mg_l2addrtype {
- MG_TCPIP_L2ADDR_BCAST,
- MG_TCPIP_L2ADDR_MCAST,
- MG_TCPIP_L2ADDR_MCAST6
- };
- #endif
- #if MG_ENABLE_TCPIP
- // Mongoose TCP/IP network interface
- struct mg_tcpip_if;
- // Hardware driver interface. Implement all function pointers to plug in a
- // new network device. Polling drivers set rx; interrupt/DMA drivers set
- // rx=NULL and push frames via mg_tcpip_qwrite() from their ISR instead.
- struct mg_tcpip_driver {
- bool (*init)(struct mg_tcpip_if *); // One-time hardware init; return false on failure
- size_t (*tx)(const void *, size_t, struct mg_tcpip_if *); // Transmit one raw frame; return bytes sent
- size_t (*rx)(void *buf, size_t len, struct mg_tcpip_if *); // Read one raw frame; return frame size, 0 if none. NULL for interrupt-driven drivers
- bool (*poll)(struct mg_tcpip_if *, bool); // Check link status; second arg is true once per second. Return true=up, false=down
- };
- // Event handler called by the TCP/IP stack for network-level events.
- // ev is one of MG_TCPIP_EV_*; ev_data type is documented per event below.
- typedef void (*mg_tcpip_event_handler_t)(struct mg_tcpip_if *ifp, int ev,
- void *ev_data);
- // clang-format off
- // Events delivered to mg_tcpip_if.fn (user) and mg_tcpip_if.pfn (driver).
- // Each entry shows the ev_data type to cast inside the handler.
- enum {
- MG_TCPIP_EV_STATE_CHANGE, // IPv4 link state changed uint8_t *(&ifp->state)
- MG_TCPIP_EV_DHCP_DNS, // DHCP assigned a DNS server uint32_t *ipaddr
- MG_TCPIP_EV_DHCP_SNTP, // DHCP assigned an SNTP server uint32_t *ipaddr
- MG_TCPIP_EV_ARP, // Raw ARP frame received struct mg_str *
- MG_TCPIP_EV_TIMER_1S, // 1-second periodic tick NULL
- MG_TCPIP_EV_WIFI_SCAN_RESULT, // Wi-Fi BSS scan entry struct mg_wifi_scan_bss_data *
- MG_TCPIP_EV_WIFI_SCAN_END, // Wi-Fi scan finished NULL
- MG_TCPIP_EV_WIFI_CONNECT_ERR, // Wi-Fi connection failed driver and chip specific
- MG_TCPIP_EV_DRIVER, // Driver-defined event driver specific
- MG_TCPIP_EV_STATE6_CHANGE, // IPv6 link state changed uint8_t *(&ifp->state6)
- MG_TCPIP_EV_USER // Starting ID for user-defined events
- };
- // clang-format on
- // Network interface. Zero-initialise, then set the fields marked "user-set"
- // before calling mg_tcpip_init(). Fields in the "internal state" section
- // below are managed by the stack; read them freely but do not modify them.
- struct mg_tcpip_if {
- // User-set configuration
- uint8_t mac[sizeof(struct mg_l2addr)]; // MAC address; must be set to a valid address
- uint32_t ip, mask, gw; // Static IPv4 address, netmask, gateway; 0 = use DHCP
- struct mg_str tx; // TX frame buffer (managed by the stack)
- bool enable_dhcp_client; // Enable DHCP client; auto-set if ip==0
- bool enable_dhcp_server; // Enable DHCP server
- bool enable_get_gateway; // DHCP server offers itself as the default gateway
- bool enable_req_dns; // DHCP client requests a DNS server address
- bool enable_req_sntp; // DHCP client requests an SNTP server address
- bool enable_fcs_check; // Verify and strip FCS from received frames
- bool enable_mac_check; // Drop frames not addressed to this MAC
- bool update_mac_hash_table; // Signal driver to refresh MAC multicast hash table
- bool is_ip_changed; // Set by stack when IP changes; triggers connection restart
- struct mg_tcpip_driver *driver; // Hardware driver; must be set before mg_tcpip_init()
- void *driver_data; // Passed to all driver functions as ifp->driver_data
- mg_tcpip_event_handler_t pfn; // Driver-level event handler; called before fn
- mg_tcpip_event_handler_t fn; // User event handler for MG_TCPIP_EV_* events
- struct mg_mgr *mgr; // Mongoose event manager; set by mg_tcpip_init()
- struct mg_queue recv_queue; // Incoming frame queue; pre-size by setting recv_queue.size
- char dhcp_name[MG_TCPIP_DHCPNAME_SIZE]; // Hostname sent in DHCP requests; defaults to "mip"
- uint16_t mtu; // IP MTU (max payload size at the IP layer)
- uint16_t framesize; // Maximum L2 frame size in bytes
- uint16_t l2mtu; // L2 frame payload, default net MTU
- #if MG_ENABLE_IPV6
- uint64_t ip6ll[2], ip6[2]; // IPv6 link-local and global addresses
- uint8_t prefix[8]; // Global prefix bytes
- uint8_t prefix_len; // Global prefix length in bits
- uint64_t gw6[2]; // IPv6 default gateway
- bool enable_slaac; // Enable SLAAC (stateless address autoconfiguration)
- bool enable_dhcp6_client; // Enable DHCPv6 client (not yet fully implemented)
- bool is_ip6_changed; // Set by stack when IPv6 address changes
- #endif
- // Internal state - read-only for users, managed by the stack
- uint8_t gwmac[sizeof(struct mg_l2addr)]; // Gateway hardware address (resolved via ARP)
- enum mg_l2type l2type; // Layer-2 type: Ethernet, PPP, etc. (see l2.h)
- union mg_l2data l2data; // Layer-2 config and state (see l2.h)
- char *dns4_url; // Active DNS server URL (set from DHCP or config)
- uint64_t now; // Current time in ms (updated each mg_mgr_poll)
- uint64_t timer_1000ms; // Timestamp of last 1-second tick
- uint64_t lease_expire; // DHCP lease expiry time in ms
- uint16_t eport; // Next ephemeral port to assign
- volatile uint32_t ndrop; // Frames received but dropped (queue full)
- volatile uint32_t nrecv; // Total frames received
- volatile uint32_t nsent; // Total frames transmitted
- volatile uint32_t nerr; // Driver-reported transmit errors
- uint8_t state; // Current IPv4 link/IP state (MG_TCPIP_STATE_*)
- #define MG_TCPIP_STATE_DOWN 0 // Physical link is down
- #define MG_TCPIP_STATE_LINK_UP 1 // Driver reports physical link is up
- #define MG_TCPIP_STATE_UP 2 // L2 is ready (e.g. PPP negotiated)
- #define MG_TCPIP_STATE_REQ 3 // DHCP REQUESTING: waiting for DHCP offer
- #define MG_TCPIP_STATE_IP 4 // IP address assigned; resolving gateway MAC
- #define MG_TCPIP_STATE_READY 5 // Fully operational; gateway MAC resolved
- bool gw_ready; // Gateway MAC address has been resolved via ARP
- #if MG_ENABLE_IPV6
- uint8_t gw6mac[sizeof(struct mg_l2addr)]; // IPv6 gateway hardware address
- uint8_t state6; // Current IPv6 link/IP state (MG_TCPIP_STATE_*)
- bool gw6_ready; // IPv6 gateway MAC address has been resolved
- #endif
- };
- // Initialises the TCP/IP stack. Calls driver->init(), allocates the TX frame
- // buffer (ifp->framesize bytes) and the RX queue. If ifp->ip == 0 and the
- // L2 type is not PPP, DHCP client is enabled automatically.
- // Must be called once after populating ifp->driver, ifp->mac, and any
- // static IP/mask/gw values.
- void mg_tcpip_init(struct mg_mgr *, struct mg_tcpip_if *);
- // Frees the TX buffer and RX queue allocated by mg_tcpip_init().
- void mg_tcpip_free(struct mg_tcpip_if *);
- // Pushes a received raw frame into ifp->recv_queue. Used by interrupt-driven
- // or DMA-based drivers (those with rx=NULL) to hand frames to the stack from
- // an ISR or DMA completion callback. Drops the frame and increments ndrop if
- // the queue is full.
- void mg_tcpip_qwrite(void *buf, size_t len, struct mg_tcpip_if *ifp);
- // Sends a broadcast ARP who-has request for ip. mac may be NULL for a plain
- // broadcast, or a non-NULL hint to set the target MAC field in the request.
- void mg_tcpip_arp_request(struct mg_tcpip_if *ifp, uint32_t ip, uint8_t *mac);
- // Built-in hardware drivers. Assign one to mg_tcpip_if.driver before calling
- // mg_tcpip_init(). Each driver also requires a corresponding driver_data
- // struct; see the matching driver header for details.
- extern struct mg_tcpip_driver mg_tcpip_driver_stm32f;
- extern struct mg_tcpip_driver mg_tcpip_driver_w5500;
- extern struct mg_tcpip_driver mg_tcpip_driver_w5100;
- extern struct mg_tcpip_driver mg_tcpip_driver_tm4c;
- extern struct mg_tcpip_driver mg_tcpip_driver_tms570;
- extern struct mg_tcpip_driver mg_tcpip_driver_stm32h;
- extern struct mg_tcpip_driver mg_tcpip_driver_imxrt;
- extern struct mg_tcpip_driver mg_tcpip_driver_same54;
- extern struct mg_tcpip_driver mg_tcpip_driver_cmsis;
- extern struct mg_tcpip_driver mg_tcpip_driver_ra;
- extern struct mg_tcpip_driver mg_tcpip_driver_xmc;
- extern struct mg_tcpip_driver mg_tcpip_driver_xmc7;
- extern struct mg_tcpip_driver mg_tcpip_driver_pico_w;
- extern struct mg_tcpip_driver mg_tcpip_driver_rw612;
- extern struct mg_tcpip_driver mg_tcpip_driver_cyw;
- extern struct mg_tcpip_driver mg_tcpip_driver_nxp_wifi;
- extern struct mg_tcpip_driver mg_tcpip_driver_st67w6;
- extern struct mg_tcpip_driver mg_tcpip_driver_atcmd;
- // SPI bus abstraction for SPI-attached network chips (e.g. W5500).
- // Populate and assign to the driver's driver_data field.
- struct mg_tcpip_spi {
- void *spi; // Opaque SPI bus handle passed to all callbacks
- void (*begin)(void *); // Assert chip-select (start of transaction)
- void (*end)(void *); // Deassert chip-select (end of transaction)
- void (*txn)(void *, uint8_t *write, uint8_t *read, size_t); // Full-duplex transfer: write and read len bytes simultaneously
- };
- // Alignment attributes for DMA-capable Ethernet descriptor buffers.
- // Use these on driver RX/TX descriptor arrays where the hardware requires
- // specific alignment.
- #ifndef MG_8BYTE_ALIGNED
- #if defined(__GNUC__)
- #define MG_8BYTE_ALIGNED __attribute__((aligned((8U))))
- #else
- #define MG_8BYTE_ALIGNED
- #endif // compiler
- #endif // 8BYTE_ALIGNED
- #ifndef MG_16BYTE_ALIGNED
- #if defined(__GNUC__)
- #define MG_16BYTE_ALIGNED __attribute__((aligned((16U))))
- #else
- #define MG_16BYTE_ALIGNED
- #endif // compiler
- #endif // 16BYTE_ALIGNED
- #ifndef MG_32BYTE_ALIGNED
- #if defined(__GNUC__)
- #define MG_32BYTE_ALIGNED __attribute__((aligned((32U))))
- #else
- #define MG_32BYTE_ALIGNED
- #endif // compiler
- #endif // 32BYTE_ALIGNED
- #ifndef MG_64BYTE_ALIGNED
- #if defined(__GNUC__)
- #define MG_64BYTE_ALIGNED __attribute__((aligned((64U))))
- #else
- #define MG_64BYTE_ALIGNED
- #endif // compiler
- #endif // 64BYTE_ALIGNED
- // Memory section attribute for Ethernet frame buffers. Define to
- // __attribute__((section(".eth_ram"))) or similar if the Ethernet DMA
- // requires buffers in a specific RAM region.
- #ifndef MG_ETH_RAM
- #define MG_ETH_RAM
- #endif
- #endif
- #if MG_ENABLE_BSD_SOCKETS
- #ifndef MG_ENABLE_BSD_PROTOTYPES
- #include <arpa/inet.h>
- #include <errno.h>
- #include <fcntl.h>
- #include <netdb.h>
- #include <netinet/in.h>
- #include <netinet/tcp.h>
- #include <poll.h>
- #include <sys/select.h>
- #include <sys/socket.h>
- #include <sys/time.h>
- #include <sys/un.h>
- #else
- #include <errno.h>
- typedef unsigned int socklen_t;
- typedef uint32_t in_addr_t;
- struct in_addr { in_addr_t s_addr; };
- struct in6_addr { uint8_t s6_addr[16]; };
- struct sockaddr { uint16_t sa_family; char sa_data[14]; };
- struct sockaddr_in {
- uint16_t sin_family;
- uint16_t sin_port;
- struct in_addr sin_addr;
- char sin_zero[8];
- };
- struct sockaddr_in6 {
- uint16_t sin6_family;
- uint16_t sin6_port;
- uint32_t sin6_flowinfo;
- struct in6_addr sin6_addr;
- uint32_t sin6_scope_id;
- };
- struct sockaddr_storage { uint16_t ss_family; char __ss_pad[126]; };
- struct hostent {
- char *h_name;
- char **h_aliases;
- int h_addrtype;
- int h_length;
- char **h_addr_list;
- };
- #define h_addr h_addr_list[0]
- struct addrinfo {
- int ai_flags;
- int ai_family;
- int ai_socktype;
- int ai_protocol;
- socklen_t ai_addrlen;
- struct sockaddr *ai_addr;
- char *ai_canonname;
- struct addrinfo *ai_next;
- };
- struct pollfd { int fd; short events; short revents; };
- #define AF_INET 2
- #define AF_INET6 10
- #define AF_UNSPEC 0
- #define PF_INET AF_INET
- #define PF_INET6 AF_INET6
- #define PF_UNSPEC AF_UNSPEC
- #define SOCK_STREAM 1
- #define SOCK_DGRAM 2
- #define IPPROTO_TCP 6
- #define IPPROTO_UDP 17
- #define INADDR_ANY 0
- #define INADDR_LOOPBACK 0x7f000001
- #define SOL_SOCKET 0xffff
- #define SO_REUSEADDR 2
- #define SO_REUSEPORT 15
- #define SO_KEEPALIVE 9
- #define SO_ERROR 4
- #define SO_BROADCAST 6
- #define SO_RCVBUF 8
- #define SO_SNDBUF 7
- #define TCP_NODELAY 1
- #define MSG_DONTWAIT 0x40
- #define MSG_NOSIGNAL 0x4000
- #define MSG_PEEK 0x02
- #define F_GETFL 3
- #define F_SETFL 4
- #define O_NONBLOCK 0x0004
- #define SHUT_RD 0
- #define SHUT_WR 1
- #define SHUT_RDWR 2
- #define AI_PASSIVE 0x0001
- #define NI_MAXHOST 1025
- #define NI_MAXSERV 32
- #ifndef EAGAIN
- #define EAGAIN 11
- #endif
- #ifndef EWOULDBLOCK
- #define EWOULDBLOCK EAGAIN
- #endif
- #ifndef EINPROGRESS
- #define EINPROGRESS 36
- #endif
- #ifndef ENOTCONN
- #define ENOTCONN 107
- #endif
- #ifndef ECONNREFUSED
- #define ECONNREFUSED 111
- #endif
- #ifndef ECONNRESET
- #define ECONNRESET 104
- #endif
- #ifndef EADDRINUSE
- #define EADDRINUSE 98
- #endif
- #ifndef ETIMEDOUT
- #define ETIMEDOUT 110
- #endif
- #define POLLIN 0x001
- #define POLLOUT 0x004
- #define POLLERR 0x008
- #define POLLHUP 0x010
- #define POLLNVAL 0x020
- uint16_t htons(uint16_t);
- uint16_t ntohs(uint16_t);
- uint32_t htonl(uint32_t);
- uint32_t ntohl(uint32_t);
- #endif // MG_ENABLE_BSD_PROTOTYPES
- #define closesocket(a) close(a)
- #ifndef MG_BSD_BACKLOG
- #define MG_BSD_BACKLOG 5
- #endif
- #ifndef MG_BSD_CONNECT_TIMEOUT_MS
- #define MG_BSD_CONNECT_TIMEOUT_MS 10000
- #endif
- // Mongoose-specific API
- void mg_bsd_init(void); // must be called before socket()
- void mg_bsd_poll(struct mg_mgr *); // process pending BSD commands
- // Transport backend: implement these OR define MG_ENABLE_FREERTOS for the built-in backend
- void *mg_bsd_transport_new(int domain, int type, int proto);
- void mg_bsd_transport_free(void *t);
- int mg_bsd_transport_listen(void *t, const struct sockaddr_in *addr);
- void *mg_bsd_transport_accept(void *t, struct sockaddr_in *peer, bool nonblock);
- ssize_t mg_bsd_transport_recv(void *t, void *buf, size_t len, bool nonblock);
- ssize_t mg_bsd_transport_send(void *t, const void *buf, size_t len, bool nonblock);
- int mg_bsd_transport_connect(void *t, const struct sockaddr_in *addr, bool nonblock);
- void mg_bsd_transport_close(void *t);
- // Standard BSD socket API
- int socket(int, int, int);
- int bind(int, const struct sockaddr *, socklen_t);
- int listen(int, int);
- int accept(int, struct sockaddr *, socklen_t *);
- int connect(int, const struct sockaddr *, socklen_t);
- ssize_t send(int, const void *, size_t, int);
- ssize_t recv(int, void *, size_t, int);
- ssize_t sendto(int, const void *, size_t, int, const struct sockaddr *, socklen_t);
- ssize_t recvfrom(int, void *, size_t, int, struct sockaddr *, socklen_t *);
- int close(int);
- int shutdown(int, int);
- int fcntl(int, int, int);
- int setsockopt(int, int, int, const void *, socklen_t);
- int getsockopt(int, int, int, void *, socklen_t *);
- int getsockname(int, struct sockaddr *, socklen_t *);
- int getpeername(int, struct sockaddr *, socklen_t *);
- int select(int, fd_set *, fd_set *, fd_set *, struct timeval *);
- int poll(struct pollfd *, unsigned int, int);
- struct hostent *gethostbyname(const char *);
- int getaddrinfo(const char *, const char *, const struct addrinfo *, struct addrinfo **);
- void freeaddrinfo(struct addrinfo *);
- int inet_pton(int, const char *, void *);
- const char *inet_ntop(int, const void *, char *, socklen_t);
- in_addr_t inet_addr(const char *);
- char *inet_ntoa(struct in_addr);
- #endif // MG_ENABLE_BSD_SOCKETS
- struct mg_tcpip_driver_atcmd_data {
- void *usart; // Opaque UART/SPI descriptor
- void (*reset)(void *); // Modem hardware reset
- void (*tx)(void *, uint8_t); // USART transmit single byte
- int (*rx)(void *); // USART receive single byte
- const char **script; // List of AT commands and expected replies
- int script_index; // Index of the current AT command in the list
- uint64_t deadline; // AT command deadline in ms
- bool no_byte_stuff; // Do not perform byte stuffing/unstuffing
- bool link; // internal use: done with AT processing
- bool unstuffing; // internal use: unstuffing state
- };
- #if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_CMSIS) && MG_ENABLE_DRIVER_CMSIS
- #include "Driver_ETH_MAC.h" // keep this include
- #include "Driver_ETH_PHY.h" // keep this include
- #endif
- #if MG_ENABLE_TCPIP && \
- ((defined(MG_ENABLE_DRIVER_CYW) && MG_ENABLE_DRIVER_CYW) || \
- (defined(MG_ENABLE_DRIVER_CYW_SDIO) && MG_ENABLE_DRIVER_CYW_SDIO))
- struct mg_tcpip_driver_cyw_firmware {
- const uint8_t *code_addr;
- size_t code_len;
- const uint8_t *nvram_addr;
- size_t nvram_len;
- const uint8_t *clm_addr;
- size_t clm_len;
- };
- struct mg_tcpip_driver_cyw_data {
- struct mg_wifi_data wifi;
- void *bus;
- struct mg_tcpip_driver_cyw_firmware *fw;
- bool hs; // use chip "high-speed" mode; otherwise SPI CPOL0 CPHA0 (DS 4.2.3 Table 6)
- };
- #define MG_TCPIP_DRIVER_INIT(mgr) \
- do { \
- static struct mg_tcpip_driver_cyw_data driver_data_; \
- static struct mg_tcpip_if mif_; \
- MG_SET_WIFI_CONFIG(&mif_, &driver_data_); \
- mif_.ip = MG_TCPIP_IP; \
- mif_.mask = MG_TCPIP_MASK; \
- mif_.gw = MG_TCPIP_GW; \
- mif_.driver = &mg_tcpip_driver_cyw; \
- mif_.driver_data = &driver_data_; \
- mif_.recv_queue.size = 8192; \
- mif_.mac[0] = 2; /* MAC read from OTP at driver init */ \
- mg_tcpip_init(mgr, &mif_); \
- MG_INFO(("Driver: cyw, MAC: %M", mg_print_mac, mif_.mac)); \
- } while (0)
- #endif
- #if MG_ENABLE_TCPIP && \
- (defined(MG_ENABLE_DRIVER_IMXRT10) && MG_ENABLE_DRIVER_IMXRT10) || \
- (defined(MG_ENABLE_DRIVER_IMXRT11) && MG_ENABLE_DRIVER_IMXRT11) || \
- (defined(MG_ENABLE_DRIVER_MCXE) && MG_ENABLE_DRIVER_MCXE)
- struct mg_tcpip_driver_imxrt_data {
- // MDC clock divider. MDC clock is derived from IPS Bus clock (ipg_clk),
- // must not exceed 2.5MHz. Configuration for clock range 2.36~2.50 MHz
- // 37.5.1.8.2, Table 37-46 : f = ipg_clk / (2(mdc_cr + 1))
- // ipg_clk mdc_cr VALUE
- // --------------------------
- // -1 <-- TODO() tell driver to guess the value
- // 25 MHz 4
- // 33 MHz 6
- // 40 MHz 7
- // 50 MHz 9
- // 66 MHz 13
- int mdc_cr; // Valid values: -1 to 63
- uint8_t phy_addr; // PHY address
- };
- #ifndef MG_TCPIP_PHY_ADDR
- #define MG_TCPIP_PHY_ADDR 2
- #endif
- #ifndef MG_DRIVER_MDC_CR
- #define MG_DRIVER_MDC_CR 24
- #endif
- #define MG_TCPIP_DRIVER_INIT(mgr) \
- do { \
- static struct mg_tcpip_driver_imxrt_data driver_data_; \
- static struct mg_tcpip_if mif_; \
- driver_data_.mdc_cr = MG_DRIVER_MDC_CR; \
- driver_data_.phy_addr = MG_TCPIP_PHY_ADDR; \
- mif_.ip = MG_TCPIP_IP; \
- mif_.mask = MG_TCPIP_MASK; \
- mif_.gw = MG_TCPIP_GW; \
- mif_.driver = &mg_tcpip_driver_imxrt; \
- mif_.driver_data = &driver_data_; \
- MG_SET_MAC_ADDRESS(mif_.mac); \
- mg_tcpip_init(mgr, &mif_); \
- MG_INFO(("Driver: imxrt, MAC: %M", mg_print_mac, mif_.mac)); \
- } while (0)
- #endif
- #if MG_ENABLE_TCPIP && \
- defined(MG_ENABLE_DRIVER_NXP_WIFI) && MG_ENABLE_DRIVER_NXP_WIFI
- struct mg_tcpip_driver_nxp_wifi_data {
- struct mg_wifi_data wifi;
- };
- #define MG_TCPIP_DRIVER_INIT(mgr) \
- do { \
- static struct mg_tcpip_driver_nxp_wifi_data driver_data_; \
- static struct mg_tcpip_if mif_; \
- MG_SET_WIFI_CONFIG(&mif_, &driver_data_); \
- mif_.ip = MG_TCPIP_IP; \
- mif_.mask = MG_TCPIP_MASK; \
- mif_.gw = MG_TCPIP_GW; \
- mif_.driver = &mg_tcpip_driver_nxp_wifi; \
- mif_.driver_data = &driver_data_; \
- mif_.recv_queue.size = 8192; \
- mif_.mac[0] = 2; /* MAC read from OTP at driver init */ \
- mg_tcpip_init(mgr, &mif_); \
- MG_INFO(("Driver: nxp wifi, MAC: %M", mg_print_mac, mif_.mac)); \
- } while (0)
- #endif
- struct mg_phy {
- uint16_t (*read_reg)(uint8_t addr, uint8_t reg);
- void (*write_reg)(uint8_t addr, uint8_t reg, uint16_t value);
- };
- // PHY configuration settings, bitmask
- enum {
- // Set if PHY LEDs are connected to ground
- MG_PHY_LEDS_ACTIVE_HIGH = (1 << 0),
- // Set when PHY clocks MAC. Otherwise, MAC clocks PHY
- MG_PHY_CLOCKS_MAC = (1 << 1)
- };
- enum { MG_PHY_SPEED_10M, MG_PHY_SPEED_100M, MG_PHY_SPEED_1000M };
- void mg_phy_init(struct mg_phy *, uint8_t addr, uint8_t config);
- bool mg_phy_up(struct mg_phy *, uint8_t addr, bool *full_duplex,
- uint8_t *speed);
- #if MG_ENABLE_TCPIP && MG_ARCH == MG_ARCH_PICOSDK && \
- defined(MG_ENABLE_DRIVER_PICO_W) && MG_ENABLE_DRIVER_PICO_W
- #include "cyw43.h" // keep this include
- #include "pico/cyw43_arch.h" // keep this include
- #include "pico/unique_id.h" // keep this include
- struct mg_tcpip_driver_pico_w_data {
- struct mg_wifi_data wifi;
- };
- #define MG_TCPIP_DRIVER_INIT(mgr) \
- do { \
- static struct mg_tcpip_driver_pico_w_data driver_data_; \
- static struct mg_tcpip_if mif_; \
- MG_SET_WIFI_CONFIG(&mif_, &driver_data_); \
- mif_.ip = MG_TCPIP_IP; \
- mif_.mask = MG_TCPIP_MASK; \
- mif_.gw = MG_TCPIP_GW; \
- mif_.driver = &mg_tcpip_driver_pico_w; \
- mif_.driver_data = &driver_data_; \
- mif_.recv_queue.size = 8192; \
- mif_.mac[0] = 2; /* MAC read from OTP at driver init */ \
- mg_tcpip_init(mgr, &mif_); \
- MG_INFO(("Driver: pico-w, MAC: %M", mg_print_mac, mif_.mac)); \
- } while (0)
- #endif
- #if MG_ENABLE_TCPIP && \
- (defined(MG_ENABLE_DRIVER_RA6) && MG_ENABLE_DRIVER_RA6) || \
- (defined(MG_ENABLE_DRIVER_RA8) && MG_ENABLE_DRIVER_RA8)
- struct mg_tcpip_driver_ra_data {
- // MDC clock "divider". MDC clock is software generated,
- uint32_t clock; // core clock frequency in Hz
- uint16_t irqno; // IRQn, R_ICU->IELSR[irqno]
- uint8_t phy_addr; // PHY address
- };
- #ifndef MG_DRIVER_CLK_FREQ
- #define MG_DRIVER_CLK_FREQ 100000000UL
- #endif
- #ifndef MG_DRIVER_IRQ_NO
- #define MG_DRIVER_IRQ_NO 0
- #endif
- #ifndef MG_TCPIP_PHY_ADDR
- #define MG_TCPIP_PHY_ADDR 0
- #endif
- #define MG_TCPIP_DRIVER_INIT(mgr) \
- do { \
- static struct mg_tcpip_driver_ra_data driver_data_; \
- static struct mg_tcpip_if mif_; \
- driver_data_.clock = MG_DRIVER_CLK_FREQ; \
- driver_data_.irqno = MG_DRIVER_IRQ_NO; \
- driver_data_.phy_addr = MG_TCPIP_PHY_ADDR; \
- mif_.ip = MG_TCPIP_IP; \
- mif_.mask = MG_TCPIP_MASK; \
- mif_.gw = MG_TCPIP_GW; \
- mif_.driver = &mg_tcpip_driver_ra; \
- mif_.driver_data = &driver_data_; \
- MG_SET_MAC_ADDRESS(mif_.mac); \
- mg_tcpip_init(mgr, &mif_); \
- MG_INFO(("Driver: ra, MAC: %M", mg_print_mac, mif_.mac)); \
- } while (0)
- #endif
- #if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_RW612) && MG_ENABLE_DRIVER_RW612
- struct mg_tcpip_driver_rw612_data {
- // 38.1.8 MII Speed Control Register (MSCR)
- // MDC clock frequency must not exceed 2.5 MHz and is calculated as follows:
- // MDC_freq = P_clock / ((mdc_cr + 1) * 2), where P_clock is the
- // peripheral bus clock.
- // IEEE802.3 clause 22 defines a minimum of 10 ns for the hold time on the
- // MDIO output. Depending on the host bus frequency, the setting may need
- // to be increased.
- int mdc_cr;
- int mdc_holdtime; // Valid values: [0-7]
- uint8_t phy_addr;
- };
- #ifndef MG_TCPIP_PHY_ADDR
- #define MG_TCPIP_PHY_ADDR 2
- #endif
- #ifndef MG_DRIVER_MDC_CR
- #define MG_DRIVER_MDC_CR 51
- #endif
- #ifndef MG_DRIVER_MDC_HOLDTIME
- #define MG_DRIVER_MDC_HOLDTIME 3
- #endif
- #define MG_TCPIP_DRIVER_INIT(mgr) \
- do { \
- static struct mg_tcpip_driver_rw612_data driver_data_; \
- static struct mg_tcpip_if mif_; \
- driver_data_.mdc_cr = MG_DRIVER_MDC_CR; \
- driver_data_.phy_addr = MG_TCPIP_PHY_ADDR; \
- mif_.ip = MG_TCPIP_IP; \
- mif_.mask = MG_TCPIP_MASK; \
- mif_.gw = MG_TCPIP_GW; \
- mif_.driver = &mg_tcpip_driver_rw612; \
- mif_.driver_data = &driver_data_; \
- MG_SET_MAC_ADDRESS(mif_.mac); \
- mg_tcpip_init(mgr, &mif_); \
- MG_INFO(("Driver: rw612, MAC: %M", mg_print_mac, mif_.mac)); \
- } while (0)
- #endif
- #if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_SAME54) && \
- MG_ENABLE_DRIVER_SAME54
- #ifndef MG_DRIVER_MDC_CR
- #define MG_DRIVER_MDC_CR 5
- #endif
- #ifndef MG_DRIVER_PHY_ADDR
- #define MG_DRIVER_PHY_ADDR 0
- #endif
- struct mg_tcpip_driver_same54_data {
- int mdc_cr;
- uint8_t phy_addr;
- };
- #define MG_TCPIP_DRIVER_INIT(mgr) \
- do { \
- static struct mg_tcpip_driver_same54_data driver_data_; \
- static struct mg_tcpip_if mif_; \
- driver_data_.mdc_cr = MG_DRIVER_MDC_CR; \
- driver_data_.phy_addr = MG_DRIVER_PHY_ADDR; \
- mif_.ip = MG_TCPIP_IP; \
- mif_.mask = MG_TCPIP_MASK; \
- mif_.gw = MG_TCPIP_GW; \
- mif_.driver = &mg_tcpip_driver_same54; \
- mif_.driver_data = &driver_data_; \
- MG_SET_MAC_ADDRESS(mif_.mac); \
- mg_tcpip_init(mgr, &mif_); \
- MG_INFO(("Driver: same54, MAC: %M", mg_print_mac, mif_.mac)); \
- } while (0)
- #endif
- #if MG_ENABLE_TCPIP && \
- (defined(MG_ENABLE_DRIVER_CYW_SDIO) && MG_ENABLE_DRIVER_CYW_SDIO)
- // Specific chip/card driver --> SDIO driver --> HAL --> SDIO hw controller
- // API with HAL for hardware controller
- // - Provide a function to init the controller (external)
- // - Provide these functions:
- struct mg_tcpip_sdio {
- void *sdio; // Opaque SDIO bus descriptor
- void (*cfg)(void *, uint8_t); // select operating parameters
- // SDIO transaction: send cmd with a possible 1-byte read or write
- bool (*txn)(void *, uint8_t cmd, uint32_t arg, uint32_t *r);
- // SDIO extended transaction: write or read len bytes, using blksz blocks
- bool (*xfr)(void *, bool write, uint32_t arg, uint16_t blksz, uint32_t *,
- uint32_t len, uint32_t *r);
- };
- // API with driver (e.g.: cyw.c)
- // Once the hardware controller has been initialized:
- // - Init card: selects the card, sets F0 block size, sets bus width and speed
- bool mg_sdio_init(struct mg_tcpip_sdio *sdio);
- // - Enable other possible functions (F1 to F7)
- bool mg_sdio_enable_f(struct mg_tcpip_sdio *sdio, unsigned int f);
- // - Wait for them to be ready
- bool mg_sdio_waitready_f(struct mg_tcpip_sdio *sdio, unsigned int f);
- // - Set their transfer block length
- bool mg_sdio_set_blksz(struct mg_tcpip_sdio *sdio, unsigned int f,
- uint16_t blksz);
- // - Transfer data to/from a function (abstracts from transaction type)
- // - Requesting a read transfer > blocksize means block transfer will be used.
- // - Drivers must have room to accomodate a whole block transfer, see sdio.c
- // - Transfers of > 1 byte --> (uint32_t *) data. 1-byte --> (uint8_t *) data
- bool mg_sdio_transfer(struct mg_tcpip_sdio *sdio, bool write, unsigned int f,
- uint32_t addr, void *data, uint32_t len);
- #endif
- #if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_ST67W6) && \
- MG_ENABLE_DRIVER_ST67W6
- struct mg_tcpip_driver_st67w6_data {
- struct mg_wifi_data wifi;
- void *spi;
- bool (*is_ready)(void); // return state of module RDY pin
- struct mg_queue send_queue; // decouple tx calls from module polls
- };
- #define MG_TCPIP_DRIVER_INIT(mgr) \
- do { \
- static struct mg_tcpip_driver_st67w6_data driver_data_; \
- static struct mg_tcpip_if mif_; \
- MG_SET_WIFI_CONFIG(&mif_, &driver_data_); \
- mif_.ip = MG_TCPIP_IP; \
- mif_.mask = MG_TCPIP_MASK; \
- mif_.gw = MG_TCPIP_GW; \
- mif_.driver = &mg_tcpip_driver_st67w6; \
- mif_.driver_data = &driver_data_; \
- mif_.recv_queue.size = 8192; \
- mif_.mac[0] = 2; /* MAC read from OTP at driver init */ \
- mg_tcpip_init(mgr, &mif_); \
- MG_INFO(("Driver: st67w6, MAC: %M", mg_print_mac, mif_.mac)); \
- } while (0)
- #endif
- #if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_STM32F) && \
- MG_ENABLE_DRIVER_STM32F
- struct mg_tcpip_driver_stm32f_data {
- // MDC clock divider. MDC clock is derived from HCLK, must not exceed 2.5MHz
- // HCLK range DIVIDER mdc_cr VALUE
- // -------------------------------------
- // -1 <-- tell driver to guess the value
- // 60-100 MHz HCLK/42 0
- // 100-150 MHz HCLK/62 1
- // 20-35 MHz HCLK/16 2
- // 35-60 MHz HCLK/26 3
- // 150-216 MHz HCLK/102 4 <-- value for Nucleo-F* on max speed
- // 216-310 MHz HCLK/124 5
- // 110, 111 Reserved
- int mdc_cr; // Valid values: -1, 0, 1, 2, 3, 4, 5
- uint8_t phy_addr; // PHY address
- };
- #ifndef MG_TCPIP_PHY_ADDR
- #define MG_TCPIP_PHY_ADDR 0
- #endif
- #ifndef MG_DRIVER_MDC_CR
- #define MG_DRIVER_MDC_CR 4
- #endif
- #if MG_ARCH == MG_ARCH_CUBE && !defined(MG_ENABLE_ETH_IRQ)
- #define MG_ENABLE_ETH_IRQ() NVIC_EnableIRQ(ETH_IRQn)
- #elif !defined(MG_ENABLE_ETH_IRQ)
- #define MG_ENABLE_ETH_IRQ()
- #endif
- #define MG_TCPIP_DRIVER_INIT(mgr) \
- do { \
- static struct mg_tcpip_driver_stm32f_data driver_data_; \
- static struct mg_tcpip_if mif_; \
- driver_data_.mdc_cr = MG_DRIVER_MDC_CR; \
- driver_data_.phy_addr = MG_TCPIP_PHY_ADDR; \
- mif_.ip = MG_TCPIP_IP; \
- mif_.mask = MG_TCPIP_MASK; \
- mif_.gw = MG_TCPIP_GW; \
- mif_.driver = &mg_tcpip_driver_stm32f; \
- mif_.driver_data = &driver_data_; \
- MG_SET_MAC_ADDRESS(mif_.mac); \
- MG_ENABLE_ETH_IRQ(); \
- mg_tcpip_init(mgr, &mif_); \
- MG_INFO(("Driver: stm32f, MAC: %M", mg_print_mac, mif_.mac)); \
- } while (0)
- #endif
- #if MG_ENABLE_TCPIP
- #if !defined(MG_ENABLE_DRIVER_STM32H)
- #define MG_ENABLE_DRIVER_STM32H 0
- #endif
- #if !defined(MG_ENABLE_DRIVER_MCXN)
- #define MG_ENABLE_DRIVER_MCXN 0
- #endif
- #if !defined(MG_ENABLE_DRIVER_STM32N)
- #define MG_ENABLE_DRIVER_STM32N 0
- #endif
- #if MG_ENABLE_DRIVER_STM32H || MG_ENABLE_DRIVER_MCXN || MG_ENABLE_DRIVER_STM32N
- struct mg_tcpip_driver_stm32h_data {
- // MDC clock divider. MDC clock is derived from HCLK, must not exceed 2.5MHz
- // HCLK range DIVIDER mdc_cr VALUE
- // -------------------------------------
- // -1 <-- tell driver to guess the value
- // 60-100 MHz HCLK/42 0
- // 100-150 MHz HCLK/62 1
- // 20-35 MHz HCLK/16 2
- // 35-60 MHz HCLK/26 3
- // 150-250 MHz HCLK/102 4 <-- value for max speed HSI
- // 250-300 MHz HCLK/124 5 <-- value for Nucleo-H* on CSI
- // 300-500 MHz HCLK/204 6
- // 500-800 MHz HCLK/324 7
- int mdc_cr; // Valid values: -1, 0, 1, 2, 3, 4, 5
- uint8_t phy_addr; // PHY address
- uint8_t phy_conf; // PHY config
- };
- #ifndef MG_TCPIP_PHY_CONF
- #define MG_TCPIP_PHY_CONF MG_PHY_CLOCKS_MAC
- #endif
- #ifndef MG_TCPIP_PHY_ADDR
- #define MG_TCPIP_PHY_ADDR 0
- #endif
- #ifndef MG_DRIVER_MDC_CR
- #define MG_DRIVER_MDC_CR 4
- #endif
- #if MG_ENABLE_DRIVER_STM32H && MG_ARCH == MG_ARCH_CUBE && !defined(MG_ENABLE_ETH_IRQ)
- #define MG_ENABLE_ETH_IRQ() NVIC_EnableIRQ(ETH_IRQn)
- #elif MG_ENABLE_DRIVER_STM32N && MG_ARCH == MG_ARCH_CUBE && !defined(MG_ENABLE_ETH_IRQ)
- #define MG_ENABLE_ETH_IRQ() NVIC_EnableIRQ(ETH1_IRQn)
- #elif !defined(MG_ENABLE_ETH_IRQ)
- #define MG_ENABLE_ETH_IRQ()
- #endif
- #if MG_ENABLE_IPV6
- #define MG_IPV6_INIT(mif) \
- do { \
- memcpy(mif.ip6ll, (uint8_t[16]) MG_TCPIP_IPV6_LINKLOCAL, 16); \
- memcpy(mif.ip6, (uint8_t[16]) MG_TCPIP_GLOBAL, 16); \
- memcpy(mif.gw6, (uint8_t[16]) MG_TCPIP_GW6, 16); \
- mif.prefix_len = MG_TCPIP_PREFIX_LEN; \
- } while(0)
- #else
- #define MG_IPV6_INIT(mif)
- #endif
- #define MG_TCPIP_DRIVER_INIT(mgr) \
- do { \
- static struct mg_tcpip_driver_stm32h_data driver_data_; \
- static struct mg_tcpip_if mif_; \
- driver_data_.mdc_cr = MG_DRIVER_MDC_CR; \
- driver_data_.phy_addr = MG_TCPIP_PHY_ADDR; \
- driver_data_.phy_conf = MG_TCPIP_PHY_CONF; \
- mif_.ip = MG_TCPIP_IP; \
- mif_.mask = MG_TCPIP_MASK; \
- mif_.gw = MG_TCPIP_GW; \
- mif_.driver = &mg_tcpip_driver_stm32h; \
- mif_.driver_data = &driver_data_; \
- MG_SET_MAC_ADDRESS(mif_.mac); \
- MG_IPV6_INIT(mif_); \
- mg_tcpip_init(mgr, &mif_); \
- MG_ENABLE_ETH_IRQ(); \
- MG_INFO(("Driver: stm32h, MAC: %M", mg_print_mac, mif_.mac)); \
- } while (0)
- #endif
- #endif
- #if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_TM4C) && MG_ENABLE_DRIVER_TM4C
- struct mg_tcpip_driver_tm4c_data {
- // MDC clock divider. MDC clock is derived from SYSCLK, must not exceed 2.5MHz
- // SYSCLK range DIVIDER mdc_cr VALUE
- // -------------------------------------
- // -1 <-- tell driver to guess the value
- // 60-100 MHz SYSCLK/42 0
- // 100-150 MHz SYSCLK/62 1 <-- value for EK-TM4C129* on max speed
- // 20-35 MHz SYSCLK/16 2
- // 35-60 MHz SYSCLK/26 3
- // 0x4-0xF Reserved
- int mdc_cr; // Valid values: -1, 0, 1, 2, 3
- };
- #ifndef MG_DRIVER_MDC_CR
- #define MG_DRIVER_MDC_CR 1
- #endif
- #define MG_TCPIP_DRIVER_INIT(mgr) \
- do { \
- static struct mg_tcpip_driver_tm4c_data driver_data_; \
- static struct mg_tcpip_if mif_; \
- driver_data_.mdc_cr = MG_DRIVER_MDC_CR; \
- mif_.ip = MG_TCPIP_IP; \
- mif_.mask = MG_TCPIP_MASK; \
- mif_.gw = MG_TCPIP_GW; \
- mif_.driver = &mg_tcpip_driver_tm4c; \
- mif_.driver_data = &driver_data_; \
- MG_SET_MAC_ADDRESS(mif_.mac); \
- mg_tcpip_init(mgr, &mif_); \
- MG_INFO(("Driver: tm4c, MAC: %M", mg_print_mac, mif_.mac)); \
- } while (0)
- #endif
- #if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_TMS570) && MG_ENABLE_DRIVER_TMS570
- struct mg_tcpip_driver_tms570_data {
- int mdc_cr;
- int phy_addr;
- };
- #ifndef MG_TCPIP_PHY_ADDR
- #define MG_TCPIP_PHY_ADDR 0
- #endif
- #ifndef MG_DRIVER_MDC_CR
- #define MG_DRIVER_MDC_CR 1
- #endif
- #define MG_TCPIP_DRIVER_INIT(mgr) \
- do { \
- static struct mg_tcpip_driver_tms570_data driver_data_; \
- static struct mg_tcpip_if mif_; \
- driver_data_.mdc_cr = MG_DRIVER_MDC_CR; \
- driver_data_.phy_addr = MG_TCPIP_PHY_ADDR; \
- mif_.ip = MG_TCPIP_IP; \
- mif_.mask = MG_TCPIP_MASK; \
- mif_.gw = MG_TCPIP_GW; \
- mif_.driver = &mg_tcpip_driver_tms570; \
- mif_.driver_data = &driver_data_; \
- MG_SET_MAC_ADDRESS(mif_.mac); \
- mg_tcpip_init(mgr, &mif_); \
- MG_INFO(("Driver: tms570, MAC: %M", mg_print_mac, mif_.mac));\
- } while (0)
- #endif
- #if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_XMC) && MG_ENABLE_DRIVER_XMC
- struct mg_tcpip_driver_xmc_data {
- // 13.2.8.1 Station Management Functions
- // MDC clock divider (). MDC clock is derived from ETH MAC clock
- // It must not exceed 2.5MHz
- // ETH Clock range DIVIDER mdc_cr VALUE
- // --------------------------------------------
- // -1 <-- tell driver to guess the value
- // 60-100 MHz ETH Clock/42 0
- // 100-150 MHz ETH Clock/62 1
- // 20-35 MHz ETH Clock/16 2
- // 35-60 MHz ETH Clock/26 3
- // 150-250 MHz ETH Clock/102 4
- // 250-300 MHz ETH Clock/124 5
- // 110, 111 Reserved
- int mdc_cr; // Valid values: -1, 0, 1, 2, 3, 4, 5
- uint8_t phy_addr;
- };
- #ifndef MG_TCPIP_PHY_ADDR
- #define MG_TCPIP_PHY_ADDR 0
- #endif
- #ifndef MG_DRIVER_MDC_CR
- #define MG_DRIVER_MDC_CR 4
- #endif
- #define MG_TCPIP_DRIVER_INIT(mgr) \
- do { \
- static struct mg_tcpip_driver_xmc_data driver_data_; \
- static struct mg_tcpip_if mif_; \
- driver_data_.mdc_cr = MG_DRIVER_MDC_CR; \
- driver_data_.phy_addr = MG_TCPIP_PHY_ADDR; \
- mif_.ip = MG_TCPIP_IP; \
- mif_.mask = MG_TCPIP_MASK; \
- mif_.gw = MG_TCPIP_GW; \
- mif_.driver = &mg_tcpip_driver_xmc; \
- mif_.driver_data = &driver_data_; \
- MG_SET_MAC_ADDRESS(mif_.mac); \
- mg_tcpip_init(mgr, &mif_); \
- MG_INFO(("Driver: xmc, MAC: %M", mg_print_mac, mif_.mac)); \
- } while (0)
- #endif
- #if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_XMC7) && MG_ENABLE_DRIVER_XMC7
- struct mg_tcpip_driver_xmc7_data {
- int mdc_cr; // Valid values: -1, 0, 1, 2, 3, 4, 5
- uint8_t phy_addr;
- };
- #ifndef MG_TCPIP_PHY_ADDR
- #define MG_TCPIP_PHY_ADDR 0
- #endif
- #ifndef MG_DRIVER_MDC_CR
- #define MG_DRIVER_MDC_CR 3
- #endif
- #define MG_TCPIP_DRIVER_INIT(mgr) \
- do { \
- static struct mg_tcpip_driver_xmc7_data driver_data_; \
- static struct mg_tcpip_if mif_; \
- driver_data_.mdc_cr = MG_DRIVER_MDC_CR; \
- driver_data_.phy_addr = MG_TCPIP_PHY_ADDR; \
- mif_.ip = MG_TCPIP_IP; \
- mif_.mask = MG_TCPIP_MASK; \
- mif_.gw = MG_TCPIP_GW; \
- mif_.driver = &mg_tcpip_driver_xmc7; \
- mif_.driver_data = &driver_data_; \
- MG_SET_MAC_ADDRESS(mif_.mac); \
- mg_tcpip_init(mgr, &mif_); \
- MG_INFO(("Driver: xmc7, MAC: %M", mg_print_mac, mif_.mac)); \
- } while (0)
- #endif
- #ifdef __cplusplus
- }
- #endif
- #endif // MONGOOSE_H
|