| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870 |
- /*
- * FreeRTOS+TCP V2.3.2 LTS Patch 1
- * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy of
- * this software and associated documentation files (the "Software"), to deal in
- * the Software without restriction, including without limitation the rights to
- * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
- * the Software, and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
- * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
- * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
- * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- *
- * http://aws.amazon.com/freertos
- * http://www.FreeRTOS.org
- */
- /**
- * @file FreeRTOS_Sockets.c
- * @brief Implements the Sockets API based on Berkeley sockets for the FreeRTOS+TCP network stack.
- * Sockets are used by the application processes to interact with the IP-task which in turn
- * interacts with the hardware.
- */
- /* Standard includes. */
- #include <stdint.h>
- #include <stdio.h>
- /* FreeRTOS includes. */
- #include "FreeRTOS.h"
- #include "task.h"
- #include "queue.h"
- #include "semphr.h"
- /* FreeRTOS+TCP includes. */
- #include "FreeRTOS_UDP_IP.h"
- #include "FreeRTOS_IP.h"
- #include "FreeRTOS_Sockets.h"
- #include "FreeRTOS_IP_Private.h"
- #include "FreeRTOS_DNS.h"
- #include "NetworkBufferManagement.h"
- /* The ItemValue of the sockets xBoundSocketListItem member holds the socket's
- * port number. */
- /** @brief Set the port number for the socket in the xBoundSocketListItem. */
- #define socketSET_SOCKET_PORT( pxSocket, usPort ) listSET_LIST_ITEM_VALUE( ( &( ( pxSocket )->xBoundSocketListItem ) ), ( usPort ) )
- /** @brief Get the port number for the socket in the xBoundSocketListItem. */
- #define socketGET_SOCKET_PORT( pxSocket ) listGET_LIST_ITEM_VALUE( ( &( ( pxSocket )->xBoundSocketListItem ) ) )
- /** @brief Test if a socket it bound which means it is either included in
- * xBoundUDPSocketsList or xBoundTCPSocketsList
- */
- #define socketSOCKET_IS_BOUND( pxSocket ) ( listLIST_ITEM_CONTAINER( &( pxSocket )->xBoundSocketListItem ) != NULL )
- /** @brief If FreeRTOS_sendto() is called on a socket that is not bound to a port
- * number then, depending on the FreeRTOSIPConfig.h settings, it might be
- * that a port number is automatically generated for the socket.
- * Automatically generated port numbers will be between
- * socketAUTO_PORT_ALLOCATION_START_NUMBER and 0xffff.
- *
- * @note Per https://tools.ietf.org/html/rfc6056, "the dynamic ports consist of
- * the range 49152-65535. However, ephemeral port selection algorithms should
- * use the whole range 1024-65535" excluding those already in use (inbound
- * or outbound).
- */
- #if !defined( socketAUTO_PORT_ALLOCATION_START_NUMBER )
- #define socketAUTO_PORT_ALLOCATION_START_NUMBER ( ( uint16_t ) 0x0400 )
- #endif
- /** @brief Maximum value of port number which can be auto assigned. */
- #define socketAUTO_PORT_ALLOCATION_MAX_NUMBER ( ( uint16_t ) 0xffff )
- /** @brief The number of octets that make up an IP address. */
- #define socketMAX_IP_ADDRESS_OCTETS 4U
- /** @brief A block time of 0 simply means "don't block". */
- #define socketDONT_BLOCK ( ( TickType_t ) 0 )
- /** @brief TCP timer period in milliseconds. */
- #if ( ( ipconfigUSE_TCP == 1 ) && !defined( ipTCP_TIMER_PERIOD_MS ) )
- #define ipTCP_TIMER_PERIOD_MS ( 1000U )
- #endif
- /* Some helper macro's for defining the 20/80 % limits of uxLittleSpace / uxEnoughSpace. */
- #define sock20_PERCENT 20U /**< 20% of the defined limit. */
- #define sock80_PERCENT 80U /**< 80% of the defined limit. */
- #define sock100_PERCENT 100U /**< 100% of the defined limit. */
- #if ( ipconfigUSE_CALLBACKS != 0 )
- static portINLINE ipDECL_CAST_PTR_FUNC_FOR_TYPE( F_TCP_UDP_Handler_t )
- {
- return ( F_TCP_UDP_Handler_t * ) pvArgument;
- }
- static portINLINE ipDECL_CAST_CONST_PTR_FUNC_FOR_TYPE( F_TCP_UDP_Handler_t )
- {
- return ( const F_TCP_UDP_Handler_t * ) pvArgument;
- }
- #endif
- /**
- * @brief Utility function to cast pointer of a type to pointer of type NetworkBufferDescriptor_t.
- *
- * @return The casted pointer.
- */
- static portINLINE ipDECL_CAST_PTR_FUNC_FOR_TYPE( NetworkBufferDescriptor_t )
- {
- return ( NetworkBufferDescriptor_t * ) pvArgument;
- }
- /**
- * @brief Utility function to cast pointer of a type to pointer of type StreamBuffer_t.
- *
- * @return The casted pointer.
- */
- static portINLINE ipDECL_CAST_PTR_FUNC_FOR_TYPE( StreamBuffer_t )
- {
- return ( StreamBuffer_t * ) pvArgument;
- }
- /*-----------------------------------------------------------*/
- /*
- * Allocate the next port number from the private allocation range.
- * TCP and UDP each have their own series of port numbers
- * ulProtocol is either ipPROTOCOL_UDP or ipPROTOCOL_TCP
- */
- static uint16_t prvGetPrivatePortNumber( BaseType_t xProtocol );
- /*
- * Return the list item from within pxList that has an item value of
- * xWantedItemValue. If there is no such list item return NULL.
- */
- static const ListItem_t * pxListFindListItemWithValue( const List_t * pxList,
- TickType_t xWantedItemValue );
- /*
- * Return pdTRUE only if pxSocket is valid and bound, as far as can be
- * determined.
- */
- static BaseType_t prvValidSocket( const FreeRTOS_Socket_t * pxSocket,
- BaseType_t xProtocol,
- BaseType_t xIsBound );
- #if ( ipconfigUSE_TCP == 1 )
- /*
- * Internal function prvSockopt_so_buffer(): sets FREERTOS_SO_SNDBUF or
- * FREERTOS_SO_RCVBUF properties of a socket.
- */
- static BaseType_t prvSockopt_so_buffer( FreeRTOS_Socket_t * pxSocket,
- int32_t lOptionName,
- const void * pvOptionValue );
- #endif /* ipconfigUSE_TCP == 1 */
- /*
- * Before creating a socket, check the validity of the parameters used
- * and find the size of the socket space, which is different for UDP and TCP
- */
- static BaseType_t prvDetermineSocketSize( BaseType_t xDomain,
- BaseType_t xType,
- BaseType_t xProtocol,
- size_t * pxSocketSize );
- #if ( ipconfigUSE_TCP == 1 )
- /*
- * Create a txStream or a rxStream, depending on the parameter 'xIsInputStream'
- */
- static StreamBuffer_t * prvTCPCreateStream( FreeRTOS_Socket_t * pxSocket,
- BaseType_t xIsInputStream );
- #endif /* ipconfigUSE_TCP == 1 */
- #if ( ipconfigUSE_TCP == 1 )
- /*
- * Called from FreeRTOS_send(): some checks which will be done before
- * sending a TCP packed.
- */
- static int32_t prvTCPSendCheck( FreeRTOS_Socket_t * pxSocket,
- size_t uxDataLength );
- #endif /* ipconfigUSE_TCP */
- #if ( ipconfigUSE_TCP == 1 )
- /*
- * When a child socket gets closed, make sure to update the child-count of the parent
- */
- static void prvTCPSetSocketCount( FreeRTOS_Socket_t const * pxSocketToDelete );
- #endif /* ipconfigUSE_TCP == 1 */
- #if ( ipconfigUSE_TCP == 1 )
- /*
- * Called from FreeRTOS_connect(): make some checks and if allowed, send a
- * message to the IP-task to start connecting to a remote socket
- */
- static BaseType_t prvTCPConnectStart( FreeRTOS_Socket_t * pxSocket,
- struct freertos_sockaddr const * pxAddress );
- #endif /* ipconfigUSE_TCP */
- #if ( ipconfigUSE_TCP == 1 )
- /*
- * Check if it makes any sense to wait for a connect event.
- * It may return: -EINPROGRESS, -EAGAIN, or 0 for OK.
- */
- static BaseType_t bMayConnect( FreeRTOS_Socket_t const * pxSocket );
- #endif /* ipconfigUSE_TCP */
- #if ( ipconfigSUPPORT_SELECT_FUNCTION == 1 )
- /* Executed by the IP-task, it will check all sockets belonging to a set */
- static void prvFindSelectedSocket( SocketSelect_t * pxSocketSet );
- #endif /* ipconfigSUPPORT_SELECT_FUNCTION == 1 */
- /*-----------------------------------------------------------*/
- /** @brief The list that contains mappings between sockets and port numbers.
- * Accesses to this list must be protected by critical sections of
- * some kind.
- */
- List_t xBoundUDPSocketsList;
- #if ipconfigUSE_TCP == 1
- /** @brief The list that contains mappings between sockets and port numbers.
- * Accesses to this list must be protected by critical sections of
- * some kind.
- */
- List_t xBoundTCPSocketsList;
- #endif /* ipconfigUSE_TCP == 1 */
- /*-----------------------------------------------------------*/
- /**
- * @brief Check whether the socket is valid or not.
- *
- * @param[in] pxSocket: The socket being checked.
- * @param[in] xProtocol: The protocol for which the socket was created.
- * @param[in] xIsBound: pdTRUE when the socket should be bound, otherwise pdFALSE.
- *
- * @return If the socket is valid, then pdPASS is returned or else, pdFAIL
- * is returned.
- */
- static BaseType_t prvValidSocket( const FreeRTOS_Socket_t * pxSocket,
- BaseType_t xProtocol,
- BaseType_t xIsBound )
- {
- BaseType_t xReturn;
- if( ( pxSocket == NULL ) || ( pxSocket == FREERTOS_INVALID_SOCKET ) )
- {
- xReturn = pdFALSE;
- }
- else if( ( xIsBound != pdFALSE ) && !socketSOCKET_IS_BOUND( pxSocket ) )
- {
- /* The caller expects the socket to be bound, but it isn't. */
- xReturn = pdFALSE;
- }
- else if( pxSocket->ucProtocol != ( uint8_t ) xProtocol )
- {
- /* Socket has a wrong type (UDP != TCP). */
- xReturn = pdFALSE;
- }
- else
- {
- xReturn = pdTRUE;
- }
- return xReturn;
- }
- /*-----------------------------------------------------------*/
- /**
- * @brief Initialise the bound TCP/UDP socket lists.
- */
- void vNetworkSocketsInit( void )
- {
- vListInitialise( &xBoundUDPSocketsList );
- #if ( ipconfigUSE_TCP == 1 )
- {
- vListInitialise( &xBoundTCPSocketsList );
- }
- #endif /* ipconfigUSE_TCP == 1 */
- }
- /*-----------------------------------------------------------*/
- /**
- * @brief Determine the socket size for the given protocol.
- *
- * @param[in] xDomain: The domain for which the size of socket is being determined.
- * @param[in] xType: Is this a datagram socket or a stream socket.
- * @param[in] xProtocol: The protocol being used.
- * @param[out] pxSocketSize: Pointer to a variable in which the size shall be returned
- * if all checks pass.
- *
- * @return pdPASS if socket size was determined and put in the parameter pxSocketSize
- * correctly, else pdFAIL.
- */
- static BaseType_t prvDetermineSocketSize( BaseType_t xDomain,
- BaseType_t xType,
- BaseType_t xProtocol,
- size_t * pxSocketSize )
- {
- BaseType_t xReturn = pdPASS;
- FreeRTOS_Socket_t const * pxSocket = NULL;
- /* Asserts must not appear before it has been determined that the network
- * task is ready - otherwise the asserts will fail. */
- if( xIPIsNetworkTaskReady() == pdFALSE )
- {
- xReturn = pdFAIL;
- }
- else
- {
- /* Only Ethernet is currently supported. */
- configASSERT( xDomain == FREERTOS_AF_INET );
- /* Check if the UDP socket-list has been initialised. */
- configASSERT( listLIST_IS_INITIALISED( &xBoundUDPSocketsList ) );
- #if ( ipconfigUSE_TCP == 1 )
- {
- /* Check if the TCP socket-list has been initialised. */
- configASSERT( listLIST_IS_INITIALISED( &xBoundTCPSocketsList ) );
- }
- #endif /* ipconfigUSE_TCP == 1 */
- if( xProtocol == FREERTOS_IPPROTO_UDP )
- {
- if( xType != FREERTOS_SOCK_DGRAM )
- {
- xReturn = pdFAIL;
- configASSERT( xReturn == pdPASS );
- }
- /* In case a UDP socket is created, do not allocate space for TCP data. */
- *pxSocketSize = ( sizeof( *pxSocket ) - sizeof( pxSocket->u ) ) + sizeof( pxSocket->u.xUDP );
- }
- #if ( ipconfigUSE_TCP == 1 )
- else if( xProtocol == FREERTOS_IPPROTO_TCP )
- {
- if( xType != FREERTOS_SOCK_STREAM )
- {
- xReturn = pdFAIL;
- configASSERT( xReturn == pdPASS );
- }
- *pxSocketSize = ( sizeof( *pxSocket ) - sizeof( pxSocket->u ) ) + sizeof( pxSocket->u.xTCP );
- }
- #endif /* ipconfigUSE_TCP == 1 */
- else
- {
- xReturn = pdFAIL;
- configASSERT( xReturn == pdPASS );
- }
- }
- /* In case configASSERT() is not used */
- ( void ) xDomain;
- ( void ) pxSocket; /* Was only used for sizeof. */
- return xReturn;
- }
- /*-----------------------------------------------------------*/
- /**
- * @brief allocate and initialise a socket.
- *
- * @param[in] xDomain: The domain in which the socket should be created.
- * @param[in] xType: The type of the socket.
- * @param[in] xProtocol: The protocol of the socket.
- *
- * @return FREERTOS_INVALID_SOCKET if the allocation failed, or if there was
- * a parameter error, otherwise a valid socket.
- */
- Socket_t FreeRTOS_socket( BaseType_t xDomain,
- BaseType_t xType,
- BaseType_t xProtocol )
- {
- FreeRTOS_Socket_t * pxSocket;
- /* Note that this value will be over-written by the call to prvDetermineSocketSize. */
- size_t uxSocketSize = 1;
- EventGroupHandle_t xEventGroup;
- Socket_t xReturn;
- if( prvDetermineSocketSize( xDomain, xType, xProtocol, &uxSocketSize ) == pdFAIL )
- {
- xReturn = FREERTOS_INVALID_SOCKET;
- }
- else
- {
- /* Allocate the structure that will hold the socket information. The
- * size depends on the type of socket: UDP sockets need less space. A
- * define 'pvPortMallocSocket' will used to allocate the necessary space.
- * By default it points to the FreeRTOS function 'pvPortMalloc()'. */
- pxSocket = ipCAST_PTR_TO_TYPE_PTR( FreeRTOS_Socket_t, pvPortMallocSocket( uxSocketSize ) );
- if( pxSocket == NULL )
- {
- xReturn = FREERTOS_INVALID_SOCKET;
- iptraceFAILED_TO_CREATE_SOCKET();
- }
- else
- {
- xEventGroup = xEventGroupCreate();
- if( xEventGroup == NULL )
- {
- vPortFreeSocket( pxSocket );
- xReturn = FREERTOS_INVALID_SOCKET;
- iptraceFAILED_TO_CREATE_EVENT_GROUP();
- }
- else
- {
- if( xProtocol == FREERTOS_IPPROTO_UDP )
- {
- iptraceMEM_STATS_CREATE( tcpSOCKET_UDP, pxSocket, uxSocketSize + sizeof( StaticEventGroup_t ) );
- }
- else
- {
- /* Lint wants at least a comment, in case the macro is empty. */
- iptraceMEM_STATS_CREATE( tcpSOCKET_TCP, pxSocket, uxSocketSize + sizeof( StaticEventGroup_t ) );
- }
- /* Clear the entire space to avoid nulling individual entries. */
- ( void ) memset( pxSocket, 0, uxSocketSize );
- pxSocket->xEventGroup = xEventGroup;
- /* Initialise the socket's members. The semaphore will be created
- * if the socket is bound to an address, for now the pointer to the
- * semaphore is just set to NULL to show it has not been created. */
- if( xProtocol == FREERTOS_IPPROTO_UDP )
- {
- vListInitialise( &( pxSocket->u.xUDP.xWaitingPacketsList ) );
- #if ( ipconfigUDP_MAX_RX_PACKETS > 0U )
- {
- pxSocket->u.xUDP.uxMaxPackets = ( UBaseType_t ) ipconfigUDP_MAX_RX_PACKETS;
- }
- #endif /* ipconfigUDP_MAX_RX_PACKETS > 0 */
- }
- vListInitialiseItem( &( pxSocket->xBoundSocketListItem ) );
- listSET_LIST_ITEM_OWNER( &( pxSocket->xBoundSocketListItem ), ipPOINTER_CAST( void *, pxSocket ) );
- pxSocket->xReceiveBlockTime = ipconfigSOCK_DEFAULT_RECEIVE_BLOCK_TIME;
- pxSocket->xSendBlockTime = ipconfigSOCK_DEFAULT_SEND_BLOCK_TIME;
- pxSocket->ucSocketOptions = ( uint8_t ) FREERTOS_SO_UDPCKSUM_OUT;
- pxSocket->ucProtocol = ( uint8_t ) xProtocol; /* protocol: UDP or TCP */
- #if ( ipconfigUSE_TCP == 1 )
- {
- if( xProtocol == FREERTOS_IPPROTO_TCP )
- {
- /* StreamSize is expressed in number of bytes */
- /* Round up buffer sizes to nearest multiple of MSS */
- pxSocket->u.xTCP.usCurMSS = ( uint16_t ) ipconfigTCP_MSS;
- pxSocket->u.xTCP.usInitMSS = ( uint16_t ) ipconfigTCP_MSS;
- pxSocket->u.xTCP.uxRxStreamSize = ( size_t ) ipconfigTCP_RX_BUFFER_LENGTH;
- pxSocket->u.xTCP.uxTxStreamSize = ( size_t ) FreeRTOS_round_up( ipconfigTCP_TX_BUFFER_LENGTH, ipconfigTCP_MSS );
- /* Use half of the buffer size of the TCP windows */
- #if ( ipconfigUSE_TCP_WIN == 1 )
- {
- pxSocket->u.xTCP.uxRxWinSize = FreeRTOS_max_uint32( 1UL, ( uint32_t ) ( pxSocket->u.xTCP.uxRxStreamSize / 2U ) / ipconfigTCP_MSS );
- pxSocket->u.xTCP.uxTxWinSize = FreeRTOS_max_uint32( 1UL, ( uint32_t ) ( pxSocket->u.xTCP.uxTxStreamSize / 2U ) / ipconfigTCP_MSS );
- }
- #else
- {
- pxSocket->u.xTCP.uxRxWinSize = 1U;
- pxSocket->u.xTCP.uxTxWinSize = 1U;
- }
- #endif
- /* The above values are just defaults, and can be overridden by
- * calling FreeRTOS_setsockopt(). No buffers will be allocated until a
- * socket is connected and data is exchanged. */
- }
- }
- #endif /* ipconfigUSE_TCP == 1 */
- xReturn = pxSocket;
- }
- }
- }
- /* Remove compiler warnings in the case the configASSERT() is not defined. */
- ( void ) xDomain;
- return xReturn;
- }
- /*-----------------------------------------------------------*/
- #if ( ipconfigSUPPORT_SELECT_FUNCTION == 1 )
- /**
- * @brief Create a socket set.
- *
- * @return The new socket set which was created, or NULL when allocation has failed.
- */
- SocketSet_t FreeRTOS_CreateSocketSet( void )
- {
- SocketSelect_t * pxSocketSet;
- pxSocketSet = ipCAST_PTR_TO_TYPE_PTR( SocketSelect_t, pvPortMalloc( sizeof( *pxSocketSet ) ) );
- if( pxSocketSet != NULL )
- {
- ( void ) memset( pxSocketSet, 0, sizeof( *pxSocketSet ) );
- pxSocketSet->xSelectGroup = xEventGroupCreate();
- if( pxSocketSet->xSelectGroup == NULL )
- {
- vPortFree( pxSocketSet );
- pxSocketSet = NULL;
- }
- else
- {
- /* Lint wants at least a comment, in case the macro is empty. */
- iptraceMEM_STATS_CREATE( tcpSOCKET_SET, pxSocketSet, sizeof( *pxSocketSet ) + sizeof( StaticEventGroup_t ) );
- }
- }
- return ( SocketSet_t ) pxSocketSet;
- }
- #endif /* ipconfigSUPPORT_SELECT_FUNCTION == 1 */
- /*-----------------------------------------------------------*/
- #if ( ipconfigSUPPORT_SELECT_FUNCTION == 1 )
- /**
- * @brief Delete a given socket set.
- *
- * @param[in] xSocketSet: The socket set being deleted.
- */
- void FreeRTOS_DeleteSocketSet( SocketSet_t xSocketSet )
- {
- SocketSelect_t * pxSocketSet = ( SocketSelect_t * ) xSocketSet;
- iptraceMEM_STATS_DELETE( pxSocketSet );
- vEventGroupDelete( pxSocketSet->xSelectGroup );
- vPortFree( pxSocketSet );
- }
- #endif /* ipconfigSUPPORT_SELECT_FUNCTION == 1 */
- /*-----------------------------------------------------------*/
- #if ( ipconfigSUPPORT_SELECT_FUNCTION == 1 )
- /**
- * @brief Add a socket to a set.
- *
- * @param[in] xSocket: The socket being added.
- * @param[in] xSocketSet: The socket set being added to.
- * @param[in] xBitsToSet: The event bits to set, a combination of the values defined
- * in 'eSelectEvent_t', for read, write, exception, etc.
- */
- void FreeRTOS_FD_SET( Socket_t xSocket,
- SocketSet_t xSocketSet,
- EventBits_t xBitsToSet )
- {
- FreeRTOS_Socket_t * pxSocket = ( FreeRTOS_Socket_t * ) xSocket;
- SocketSelect_t * pxSocketSet = ( SocketSelect_t * ) xSocketSet;
- configASSERT( pxSocket != NULL );
- configASSERT( xSocketSet != NULL );
- /* Make sure we're not adding bits which are reserved for internal use,
- * such as eSELECT_CALL_IP */
- pxSocket->xSelectBits |= xBitsToSet & ( ( EventBits_t ) eSELECT_ALL );
- if( ( pxSocket->xSelectBits & ( ( EventBits_t ) eSELECT_ALL ) ) != ( EventBits_t ) 0U )
- {
- /* Adding a socket to a socket set. */
- pxSocket->pxSocketSet = ( SocketSelect_t * ) xSocketSet;
- /* Now have the IP-task call vSocketSelect() to see if the set contains
- * any sockets which are 'ready' and set the proper bits. */
- prvFindSelectedSocket( pxSocketSet );
- }
- }
- #endif /* ipconfigSUPPORT_SELECT_FUNCTION == 1 */
- /*-----------------------------------------------------------*/
- #if ( ipconfigSUPPORT_SELECT_FUNCTION == 1 )
- /**
- * @brief Clear select bits for a socket. If the mask becomes 0,
- * remove the socket from the set.
- *
- * @param[in] xSocket: The socket whose select bits are being cleared.
- * @param[in] xSocketSet: The socket set of the socket.
- * @param[in] xBitsToClear: The bits to be cleared. Every '1' means that the
- * corresponding bit will be cleared. See 'eSelectEvent_t' for
- * the possible values.
- */
- void FreeRTOS_FD_CLR( Socket_t xSocket,
- SocketSet_t xSocketSet,
- EventBits_t xBitsToClear )
- {
- FreeRTOS_Socket_t * pxSocket = ( FreeRTOS_Socket_t * ) xSocket;
- configASSERT( pxSocket != NULL );
- configASSERT( xSocketSet != NULL );
- pxSocket->xSelectBits &= ~( xBitsToClear & ( ( EventBits_t ) eSELECT_ALL ) );
- if( ( pxSocket->xSelectBits & ( ( EventBits_t ) eSELECT_ALL ) ) != ( EventBits_t ) 0U )
- {
- pxSocket->pxSocketSet = ( SocketSelect_t * ) xSocketSet;
- }
- else
- {
- /* disconnect it from the socket set */
- pxSocket->pxSocketSet = NULL;
- }
- }
- #endif /* ipconfigSUPPORT_SELECT_FUNCTION == 1 */
- /*-----------------------------------------------------------*/
- #if ( ipconfigSUPPORT_SELECT_FUNCTION == 1 )
- /**
- * @brief Test if a socket belongs to a socket-set and if so, which event bit(s)
- * are set.
- *
- * @param[in] xSocket: The socket of interest.
- * @param[in] xSocketSet: The socket set to which the socket belongs.
- *
- * @return If the socket belongs to the socket set: the event bits, otherwise zero.
- */
- EventBits_t FreeRTOS_FD_ISSET( Socket_t xSocket,
- SocketSet_t xSocketSet )
- {
- EventBits_t xReturn;
- const FreeRTOS_Socket_t * pxSocket = ( const FreeRTOS_Socket_t * ) xSocket;
- configASSERT( pxSocket != NULL );
- configASSERT( xSocketSet != NULL );
- if( xSocketSet == ( SocketSet_t ) pxSocket->pxSocketSet )
- {
- /* Make sure we're not adding bits which are reserved for internal
- * use. */
- xReturn = pxSocket->xSocketBits & ( ( EventBits_t ) eSELECT_ALL );
- }
- else
- {
- xReturn = 0;
- }
- return xReturn;
- }
- #endif /* ipconfigSUPPORT_SELECT_FUNCTION == 1 */
- /*-----------------------------------------------------------*/
- #if ( ipconfigSUPPORT_SELECT_FUNCTION == 1 )
- /**
- * @brief The select() statement: wait for an event to occur on any of the sockets
- * included in a socket set.
- *
- * @param[in] xSocketSet: The socket set including the sockets on which we are
- * waiting for an event to occur.
- * @param[in] xBlockTimeTicks: Maximum time ticks to wait for an event to occur.
- * If the value is 'portMAX_DELAY' then the function will wait
- * indefinitely for an event to occur.
- *
- * @return The socket which might have triggered the event bit.
- */
- BaseType_t FreeRTOS_select( SocketSet_t xSocketSet,
- TickType_t xBlockTimeTicks )
- {
- TimeOut_t xTimeOut;
- TickType_t xRemainingTime;
- SocketSelect_t * pxSocketSet = ( SocketSelect_t * ) xSocketSet;
- EventBits_t uxResult;
- configASSERT( xSocketSet != NULL );
- /* Only in the first round, check for non-blocking */
- xRemainingTime = xBlockTimeTicks;
- /* Fetch the current time */
- vTaskSetTimeOutState( &xTimeOut );
- for( ; ; )
- {
- /* Find a socket which might have triggered the bit
- * This function might return immediately or block for a limited time */
- uxResult = xEventGroupWaitBits( pxSocketSet->xSelectGroup, ( ( EventBits_t ) eSELECT_ALL ), pdFALSE, pdFALSE, xRemainingTime );
- #if ( ipconfigSUPPORT_SIGNALS != 0 )
- {
- if( ( uxResult & ( ( EventBits_t ) eSELECT_INTR ) ) != 0U )
- {
- ( void ) xEventGroupClearBits( pxSocketSet->xSelectGroup, ( EventBits_t ) eSELECT_INTR );
- FreeRTOS_debug_printf( ( "FreeRTOS_select: interrupted\n" ) );
- break;
- }
- }
- #endif /* ipconfigSUPPORT_SIGNALS */
- /* Have the IP-task find the socket which had an event */
- prvFindSelectedSocket( pxSocketSet );
- uxResult = xEventGroupGetBits( pxSocketSet->xSelectGroup );
- if( uxResult != 0U )
- {
- break;
- }
- /* Has the timeout been reached? */
- if( xTaskCheckForTimeOut( &xTimeOut, &xRemainingTime ) != pdFALSE )
- {
- break;
- }
- }
- return ( BaseType_t ) uxResult;
- }
- #endif /* ipconfigSUPPORT_SELECT_FUNCTION */
- /*-----------------------------------------------------------*/
- #if ( ipconfigSUPPORT_SELECT_FUNCTION == 1 )
- /**
- * @brief Send a message to the IP-task to have it check all sockets belonging to
- * 'pxSocketSet'
- *
- * @param[in] pxSocketSet: The socket set being asked to check.
- */
- static void prvFindSelectedSocket( SocketSelect_t * pxSocketSet )
- {
- IPStackEvent_t xSelectEvent;
- #if ( ipconfigSELECT_USES_NOTIFY != 0 )
- SocketSelectMessage_t xSelectMessage;
- #endif
- xSelectEvent.eEventType = eSocketSelectEvent;
- #if ( ipconfigSELECT_USES_NOTIFY != 0 )
- {
- xSelectMessage.pxSocketSet = pxSocketSet;
- xSelectMessage.xTaskhandle = xTaskGetCurrentTaskHandle();
- xSelectEvent.pvData = &( xSelectMessage );
- }
- #else
- {
- xSelectEvent.pvData = pxSocketSet;
- /* while the IP-task works on the request, the API will block on
- * 'eSELECT_CALL_IP'. So clear it first. */
- ( void ) xEventGroupClearBits( pxSocketSet->xSelectGroup, ( BaseType_t ) eSELECT_CALL_IP );
- }
- #endif /* if ( ipconfigSELECT_USES_NOTIFY != 0 ) */
- /* Now send the socket select event */
- if( xSendEventStructToIPTask( &xSelectEvent, ( TickType_t ) portMAX_DELAY ) == pdFAIL )
- {
- /* Oops, we failed to wake-up the IP task. No use to wait for it. */
- FreeRTOS_debug_printf( ( "prvFindSelectedSocket: failed\n" ) );
- }
- else
- {
- /* As soon as the IP-task is ready, it will set 'eSELECT_CALL_IP' to
- * wakeup the calling API */
- #if ( ipconfigSELECT_USES_NOTIFY != 0 )
- {
- ( void ) ulTaskNotifyTake( pdFALSE, portMAX_DELAY );
- }
- #else
- {
- ( void ) xEventGroupWaitBits( pxSocketSet->xSelectGroup, ( BaseType_t ) eSELECT_CALL_IP, pdTRUE, pdFALSE, portMAX_DELAY );
- }
- #endif
- }
- }
- #endif /* ipconfigSUPPORT_SELECT_FUNCTION == 1 */
- /*-----------------------------------------------------------*/
- /**
- * @brief Receive data from a bound socket. In this library, the function
- * can only be used with connection-less sockets (UDP). For TCP sockets,
- * please use FreeRTOS_recv().
- *
- * @param[in] xSocket: The socket to which the data is sent i.e. the
- * listening socket.
- * @param[out] pvBuffer: The buffer in which the data being received is to
- * be stored.
- * @param[in] uxBufferLength: The length of the buffer.
- * @param[in] xFlags: The flags to indicate preferences while calling this function.
- * @param[out] pxSourceAddress: The source address from which the data is being sent.
- * @param[out] pxSourceAddressLength: This parameter is used only to adhere to Berkeley
- * sockets standard. It is not used internally.
- *
- * @return The number of bytes received. Or else, an error code is returned. When it
- * returns a negative value, the cause can be looked-up in
- * 'FreeRTOS_errno_TCP.h'.
- */
- int32_t FreeRTOS_recvfrom( Socket_t xSocket,
- void * pvBuffer,
- size_t uxBufferLength,
- BaseType_t xFlags,
- struct freertos_sockaddr * pxSourceAddress,
- socklen_t * pxSourceAddressLength )
- {
- BaseType_t lPacketCount;
- NetworkBufferDescriptor_t * pxNetworkBuffer;
- const void * pvCopySource;
- FreeRTOS_Socket_t const * pxSocket = xSocket;
- TickType_t xRemainingTime = ( TickType_t ) 0; /* Obsolete assignment, but some compilers output a warning if its not done. */
- BaseType_t xTimed = pdFALSE;
- TimeOut_t xTimeOut;
- int32_t lReturn;
- EventBits_t xEventBits = ( EventBits_t ) 0;
- size_t uxPayloadLength;
- if( prvValidSocket( pxSocket, FREERTOS_IPPROTO_UDP, pdTRUE ) == pdFALSE )
- {
- lReturn = -pdFREERTOS_ERRNO_EINVAL;
- }
- else
- {
- lPacketCount = ( BaseType_t ) listCURRENT_LIST_LENGTH( &( pxSocket->u.xUDP.xWaitingPacketsList ) );
- /* The function prototype is designed to maintain the expected Berkeley
- * sockets standard, but this implementation does not use all the parameters. */
- ( void ) pxSourceAddressLength;
- while( lPacketCount == 0 )
- {
- if( xTimed == pdFALSE )
- {
- /* Check to see if the socket is non blocking on the first
- * iteration. */
- xRemainingTime = pxSocket->xReceiveBlockTime;
- if( xRemainingTime == ( TickType_t ) 0 )
- {
- #if ( ipconfigSUPPORT_SIGNALS != 0 )
- {
- /* Just check for the interrupt flag. */
- xEventBits = xEventGroupWaitBits( pxSocket->xEventGroup, ( EventBits_t ) eSOCKET_INTR,
- pdTRUE /*xClearOnExit*/, pdFALSE /*xWaitAllBits*/, socketDONT_BLOCK );
- }
- #endif /* ipconfigSUPPORT_SIGNALS */
- break;
- }
- if( ( ( ( UBaseType_t ) xFlags ) & ( ( UBaseType_t ) FREERTOS_MSG_DONTWAIT ) ) != 0U )
- {
- break;
- }
- /* To ensure this part only executes once. */
- xTimed = pdTRUE;
- /* Fetch the current time. */
- vTaskSetTimeOutState( &xTimeOut );
- }
- /* Wait for arrival of data. While waiting, the IP-task may set the
- * 'eSOCKET_RECEIVE' bit in 'xEventGroup', if it receives data for this
- * socket, thus unblocking this API call. */
- xEventBits = xEventGroupWaitBits( pxSocket->xEventGroup, ( ( EventBits_t ) eSOCKET_RECEIVE ) | ( ( EventBits_t ) eSOCKET_INTR ),
- pdTRUE /*xClearOnExit*/, pdFALSE /*xWaitAllBits*/, xRemainingTime );
- #if ( ipconfigSUPPORT_SIGNALS != 0 )
- {
- if( ( xEventBits & ( EventBits_t ) eSOCKET_INTR ) != 0U )
- {
- if( ( xEventBits & ( EventBits_t ) eSOCKET_RECEIVE ) != 0U )
- {
- /* Shouldn't have cleared the eSOCKET_RECEIVE flag. */
- ( void ) xEventGroupSetBits( pxSocket->xEventGroup, ( EventBits_t ) eSOCKET_RECEIVE );
- }
- break;
- }
- }
- #else /* if ( ipconfigSUPPORT_SIGNALS != 0 ) */
- {
- ( void ) xEventBits;
- }
- #endif /* ipconfigSUPPORT_SIGNALS */
- lPacketCount = ( BaseType_t ) listCURRENT_LIST_LENGTH( &( pxSocket->u.xUDP.xWaitingPacketsList ) );
- if( lPacketCount != 0 )
- {
- break;
- }
- /* Has the timeout been reached ? */
- if( xTaskCheckForTimeOut( &xTimeOut, &xRemainingTime ) != pdFALSE )
- {
- break;
- }
- } /* while( lPacketCount == 0 ) */
- if( lPacketCount != 0 )
- {
- taskENTER_CRITICAL();
- {
- /* The owner of the list item is the network buffer. */
- pxNetworkBuffer = ipCAST_PTR_TO_TYPE_PTR( NetworkBufferDescriptor_t, listGET_OWNER_OF_HEAD_ENTRY( &( pxSocket->u.xUDP.xWaitingPacketsList ) ) );
- if( ( ( UBaseType_t ) xFlags & ( UBaseType_t ) FREERTOS_MSG_PEEK ) == 0U )
- {
- /* Remove the network buffer from the list of buffers waiting to
- * be processed by the socket. */
- ( void ) uxListRemove( &( pxNetworkBuffer->xBufferListItem ) );
- }
- }
- taskEXIT_CRITICAL();
- /* The returned value is the length of the payload data, which is
- * calculated at the total packet size minus the headers.
- * The validity of `xDataLength` prvProcessIPPacket has been confirmed
- * in 'prvProcessIPPacket()'. */
- uxPayloadLength = pxNetworkBuffer->xDataLength - sizeof( UDPPacket_t );
- lReturn = ( int32_t ) uxPayloadLength;
- if( pxSourceAddress != NULL )
- {
- pxSourceAddress->sin_port = pxNetworkBuffer->usPort;
- pxSourceAddress->sin_addr = pxNetworkBuffer->ulIPAddress;
- }
- if( ( ( UBaseType_t ) xFlags & ( UBaseType_t ) FREERTOS_ZERO_COPY ) == 0U )
- {
- /* The zero copy flag is not set. Truncate the length if it won't
- * fit in the provided buffer. */
- if( lReturn > ( int32_t ) uxBufferLength )
- {
- iptraceRECVFROM_DISCARDING_BYTES( ( uxBufferLength - lReturn ) );
- lReturn = ( int32_t ) uxBufferLength;
- }
- /* Copy the received data into the provided buffer, then release the
- * network buffer. */
- pvCopySource = ( const void * ) &pxNetworkBuffer->pucEthernetBuffer[ ipUDP_PAYLOAD_OFFSET_IPv4 ];
- ( void ) memcpy( pvBuffer, pvCopySource, ( size_t ) lReturn );
- if( ( ( UBaseType_t ) xFlags & ( UBaseType_t ) FREERTOS_MSG_PEEK ) == 0U )
- {
- vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );
- }
- }
- else
- {
- /* The zero copy flag was set. pvBuffer is not a buffer into which
- * the received data can be copied, but a pointer that must be set to
- * point to the buffer in which the received data has already been
- * placed. */
- *( ( void ** ) pvBuffer ) = ipPOINTER_CAST( void *, &( pxNetworkBuffer->pucEthernetBuffer[ ipUDP_PAYLOAD_OFFSET_IPv4 ] ) );
- }
- }
- #if ( ipconfigSUPPORT_SIGNALS != 0 )
- else if( ( xEventBits & ( EventBits_t ) eSOCKET_INTR ) != 0U )
- {
- lReturn = -pdFREERTOS_ERRNO_EINTR;
- iptraceRECVFROM_INTERRUPTED();
- }
- #endif /* ipconfigSUPPORT_SIGNALS */
- else
- {
- lReturn = -pdFREERTOS_ERRNO_EWOULDBLOCK;
- iptraceRECVFROM_TIMEOUT();
- }
- }
- return lReturn;
- }
- /*-----------------------------------------------------------*/
- /**
- * @brief Send data to a socket. The socket must have already been created by a
- * successful call to FreeRTOS_socket(). It works for UDP-sockets only.
- *
- * @param[in] xSocket: The socket being sent to.
- * @param[in] pvBuffer: Pointer to the data being sent.
- * @param[in] uxTotalDataLength: Length (in bytes) of the data being sent.
- * @param[in] xFlags: Flags used to communicate preferences to the function.
- * Possibly FREERTOS_MSG_DONTWAIT and/or FREERTOS_ZERO_COPY.
- * @param[in] pxDestinationAddress: The address to which the data is to be sent.
- * @param[in] xDestinationAddressLength: This parameter is present to adhere to the
- * Berkeley sockets standard. Else, it is not used.
- *
- * @return When positive: the total number of bytes sent, when negative an error
- * has occurred: it can be looked-up in 'FreeRTOS_errno_TCP.h'.
- */
- int32_t FreeRTOS_sendto( Socket_t xSocket,
- const void * pvBuffer,
- size_t uxTotalDataLength,
- BaseType_t xFlags,
- const struct freertos_sockaddr * pxDestinationAddress,
- socklen_t xDestinationAddressLength )
- {
- NetworkBufferDescriptor_t * pxNetworkBuffer;
- void * pvCopyDest;
- IPStackEvent_t xStackTxEvent = { eStackTxEvent, NULL };
- TimeOut_t xTimeOut;
- TickType_t xTicksToWait;
- int32_t lReturn = 0;
- FreeRTOS_Socket_t const * pxSocket;
- const size_t uxMaxPayloadLength = ipMAX_UDP_PAYLOAD_LENGTH;
- const size_t uxPayloadOffset = ipUDP_PAYLOAD_OFFSET_IPv4;
- pxSocket = ( FreeRTOS_Socket_t * ) xSocket;
- /* The function prototype is designed to maintain the expected Berkeley
- * sockets standard, but this implementation does not use all the
- * parameters. */
- ( void ) xDestinationAddressLength;
- configASSERT( pvBuffer != NULL );
- if( uxTotalDataLength <= ( size_t ) uxMaxPayloadLength )
- {
- /* If the socket is not already bound to an address, bind it now.
- * Passing NULL as the address parameter tells FreeRTOS_bind() to select
- * the address to bind to. */
- if( socketSOCKET_IS_BOUND( pxSocket ) ||
- ( FreeRTOS_bind( xSocket, NULL, 0U ) == 0 ) )
- {
- xTicksToWait = pxSocket->xSendBlockTime;
- #if ( ipconfigUSE_CALLBACKS != 0 )
- {
- if( xIsCallingFromIPTask() != pdFALSE )
- {
- /* If this send function is called from within a call-back
- * handler it may not block, otherwise chances would be big to
- * get a deadlock: the IP-task waiting for itself. */
- xTicksToWait = ( TickType_t ) 0;
- }
- }
- #endif /* ipconfigUSE_CALLBACKS */
- if( ( ( UBaseType_t ) xFlags & ( UBaseType_t ) FREERTOS_MSG_DONTWAIT ) != 0U )
- {
- xTicksToWait = ( TickType_t ) 0;
- }
- if( ( ( UBaseType_t ) xFlags & ( UBaseType_t ) FREERTOS_ZERO_COPY ) == 0U )
- {
- /* Zero copy is not set, so obtain a network buffer into
- * which the payload will be copied. */
- vTaskSetTimeOutState( &xTimeOut );
- /* Block until a buffer becomes available, or until a
- * timeout has been reached */
- pxNetworkBuffer = pxGetNetworkBufferWithDescriptor( uxPayloadOffset + uxTotalDataLength, xTicksToWait );
- if( pxNetworkBuffer != NULL )
- {
- pvCopyDest = ( void * ) &pxNetworkBuffer->pucEthernetBuffer[ uxPayloadOffset ];
- ( void ) memcpy( pvCopyDest, pvBuffer, uxTotalDataLength );
- if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdTRUE )
- {
- /* The entire block time has been used up. */
- xTicksToWait = ( TickType_t ) 0;
- }
- }
- }
- else
- {
- /* When zero copy is used, pvBuffer is a pointer to the
- * payload of a buffer that has already been obtained from the
- * stack. Obtain the network buffer pointer from the buffer. */
- pxNetworkBuffer = pxUDPPayloadBuffer_to_NetworkBuffer( pvBuffer );
- }
- if( pxNetworkBuffer != NULL )
- {
- /* xDataLength is the size of the total packet, including the Ethernet header. */
- pxNetworkBuffer->xDataLength = uxTotalDataLength + sizeof( UDPPacket_t );
- pxNetworkBuffer->usPort = pxDestinationAddress->sin_port;
- pxNetworkBuffer->usBoundPort = ( uint16_t ) socketGET_SOCKET_PORT( pxSocket );
- pxNetworkBuffer->ulIPAddress = pxDestinationAddress->sin_addr;
- /* The socket options are passed to the IP layer in the
- * space that will eventually get used by the Ethernet header. */
- pxNetworkBuffer->pucEthernetBuffer[ ipSOCKET_OPTIONS_OFFSET ] = pxSocket->ucSocketOptions;
- /* Tell the networking task that the packet needs sending. */
- xStackTxEvent.pvData = pxNetworkBuffer;
- /* Ask the IP-task to send this packet */
- if( xSendEventStructToIPTask( &xStackTxEvent, xTicksToWait ) == pdPASS )
- {
- /* The packet was successfully sent to the IP task. */
- lReturn = ( int32_t ) uxTotalDataLength;
- #if ( ipconfigUSE_CALLBACKS == 1 )
- {
- if( ipconfigIS_VALID_PROG_ADDRESS( pxSocket->u.xUDP.pxHandleSent ) )
- {
- pxSocket->u.xUDP.pxHandleSent( xSocket, uxTotalDataLength );
- }
- }
- #endif /* ipconfigUSE_CALLBACKS */
- }
- else
- {
- /* If the buffer was allocated in this function, release
- * it. */
- if( ( ( UBaseType_t ) xFlags & ( UBaseType_t ) FREERTOS_ZERO_COPY ) == 0U )
- {
- vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );
- }
- iptraceSTACK_TX_EVENT_LOST( ipSTACK_TX_EVENT );
- }
- }
- else
- {
- /* If errno was available, errno would be set to
- * FREERTOS_ENOPKTS. As it is, the function must return the
- * number of transmitted bytes, so the calling function knows
- * how much data was actually sent. */
- iptraceNO_BUFFER_FOR_SENDTO();
- }
- }
- else
- {
- /* No comment. */
- iptraceSENDTO_SOCKET_NOT_BOUND();
- }
- }
- else
- {
- /* The data is longer than the available buffer space. */
- iptraceSENDTO_DATA_TOO_LONG();
- }
- return lReturn;
- } /* Tested */
- /*-----------------------------------------------------------*/
- /**
- * @brief binds a socket to a local port number. If port 0 is provided,
- * a system provided port number will be assigned. This function
- * can be used for both UDP and TCP sockets. The actual binding
- * will be performed by the IP-task to avoid mutual access to the
- * bound-socket-lists (xBoundUDPSocketsList or xBoundTCPSocketsList).
- *
- * @param[in] xSocket: The socket being bound.
- * @param[in] pxAddress: The address struct carrying the port number to which
- * this socket is to be bound.
- * @param[in] xAddressLength: This parameter is not used internally. The
- * function signature is used to adhere to standard
- * Berkeley sockets API.
- *
- * @return The return value is 0 if the bind is successful.
- * If some error occurred, then a negative value is returned.
- */
- BaseType_t FreeRTOS_bind( Socket_t xSocket,
- struct freertos_sockaddr const * pxAddress,
- socklen_t xAddressLength )
- {
- IPStackEvent_t xBindEvent;
- FreeRTOS_Socket_t * pxSocket = ( FreeRTOS_Socket_t * ) xSocket;
- BaseType_t xReturn = 0;
- ( void ) xAddressLength;
- configASSERT( xIsCallingFromIPTask() == pdFALSE );
- if( ( pxSocket == NULL ) || ( pxSocket == FREERTOS_INVALID_SOCKET ) )
- {
- xReturn = -pdFREERTOS_ERRNO_EINVAL;
- }
- /* Once a socket is bound to a port, it can not be bound to a different
- * port number */
- else if( socketSOCKET_IS_BOUND( pxSocket ) )
- {
- /* The socket is already bound. */
- FreeRTOS_debug_printf( ( "vSocketBind: Socket already bound to %d\n", pxSocket->usLocalPort ) );
- xReturn = -pdFREERTOS_ERRNO_EINVAL;
- }
- else
- {
- /* Prepare a messages to the IP-task in order to perform the binding.
- * The desired port number will be passed in usLocalPort. */
- xBindEvent.eEventType = eSocketBindEvent;
- xBindEvent.pvData = xSocket;
- if( pxAddress != NULL )
- {
- pxSocket->usLocalPort = FreeRTOS_ntohs( pxAddress->sin_port );
- }
- else
- {
- /* Caller wants to bind to a random port number. */
- pxSocket->usLocalPort = 0U;
- }
- /* portMAX_DELAY is used as a the time-out parameter, as binding *must*
- * succeed before the socket can be used. _RB_ The use of an infinite
- * block time needs be changed as it could result in the task hanging. */
- if( xSendEventStructToIPTask( &xBindEvent, ( TickType_t ) portMAX_DELAY ) == pdFAIL )
- {
- /* Failed to wake-up the IP-task, no use to wait for it */
- FreeRTOS_debug_printf( ( "FreeRTOS_bind: send event failed\n" ) );
- xReturn = -pdFREERTOS_ERRNO_ECANCELED;
- }
- else
- {
- /* The IP-task will set the 'eSOCKET_BOUND' bit when it has done its
- * job. */
- ( void ) xEventGroupWaitBits( pxSocket->xEventGroup, ( EventBits_t ) eSOCKET_BOUND, pdTRUE /*xClearOnExit*/, pdFALSE /*xWaitAllBits*/, portMAX_DELAY );
- if( !socketSOCKET_IS_BOUND( pxSocket ) )
- {
- xReturn = -pdFREERTOS_ERRNO_EINVAL;
- }
- }
- }
- return xReturn;
- }
- /*-----------------------------------------------------------*/
- /**
- * @brief Internal version of bind() that should not be called directly.
- * 'xInternal' is used for TCP sockets only: it allows to have several
- * (connected) child sockets bound to the same server port.
- *
- * @param[in] pxSocket: The socket is to be bound.
- * @param[in] pxBindAddress: The port to which this socket should be bound.
- * @param[in] uxAddressLength: The address length.
- * @param[in] xInternal: pdTRUE is calling internally, else pdFALSE.
- *
- * @return If the socket was bound to a port successfully, then a 0 is returned.
- * Or else, an error code is returned.
- */
- BaseType_t vSocketBind( FreeRTOS_Socket_t * pxSocket,
- struct freertos_sockaddr * pxBindAddress,
- size_t uxAddressLength,
- BaseType_t xInternal )
- {
- BaseType_t xReturn = 0; /* In Berkeley sockets, 0 means pass for bind(). */
- List_t * pxSocketList;
- struct freertos_sockaddr * pxAddress = pxBindAddress;
- #if ( ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND == 1 )
- struct freertos_sockaddr xAddress;
- #endif /* ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND */
- #if ( ipconfigUSE_TCP == 1 )
- if( pxSocket->ucProtocol == ( uint8_t ) FREERTOS_IPPROTO_TCP )
- {
- pxSocketList = &xBoundTCPSocketsList;
- }
- else
- #endif /* ipconfigUSE_TCP == 1 */
- {
- pxSocketList = &xBoundUDPSocketsList;
- }
- /* The function prototype is designed to maintain the expected Berkeley
- * sockets standard, but this implementation does not use all the parameters. */
- ( void ) uxAddressLength;
- configASSERT( pxSocket != NULL );
- configASSERT( pxSocket != FREERTOS_INVALID_SOCKET );
- #if ( ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND == 1 )
- {
- /* pxAddress will be NULL if sendto() was called on a socket without the
- * socket being bound to an address. In this case, automatically allocate
- * an address to the socket. There is a small chance that the allocated
- * port will already be in use - if that is the case, then the check below
- * [pxListFindListItemWithValue()] will result in an error being returned. */
- if( pxAddress == NULL )
- {
- pxAddress = &xAddress;
- /* Put the port to zero to be assigned later. */
- pxAddress->sin_port = 0U;
- }
- }
- #endif /* ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND == 1 */
- /* Sockets must be bound before calling FreeRTOS_sendto() if
- * ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND is not set to 1. */
- configASSERT( pxAddress != NULL );
- #if ( ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND == 1 )
- /* pxAddress is not NULL, no testing needed. */
- #else
- if( pxAddress != NULL )
- #endif
- {
- /* Add a do-while loop to facilitate use of 'break' statements. */
- do
- {
- if( pxAddress->sin_port == 0U )
- {
- pxAddress->sin_port = prvGetPrivatePortNumber( ( BaseType_t ) pxSocket->ucProtocol );
- if( pxAddress->sin_port == ( uint16_t ) 0U )
- {
- xReturn = -pdFREERTOS_ERRNO_EADDRNOTAVAIL;
- break;
- }
- }
- /* If vSocketBind() is called from the API FreeRTOS_bind() it has been
- * confirmed that the socket was not yet bound to a port. If it is called
- * from the IP-task, no such check is necessary. */
- /* Check to ensure the port is not already in use. If the bind is
- * called internally, a port MAY be used by more than one socket. */
- if( ( ( xInternal == pdFALSE ) || ( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_TCP ) ) &&
- ( pxListFindListItemWithValue( pxSocketList, ( TickType_t ) pxAddress->sin_port ) != NULL ) )
- {
- FreeRTOS_debug_printf( ( "vSocketBind: %sP port %d in use\n",
- ( pxSocket->ucProtocol == ( uint8_t ) FREERTOS_IPPROTO_TCP ) ? "TC" : "UD",
- FreeRTOS_ntohs( pxAddress->sin_port ) ) );
- xReturn = -pdFREERTOS_ERRNO_EADDRINUSE;
- }
- else
- {
- /* Allocate the port number to the socket.
- * This macro will set 'xBoundSocketListItem->xItemValue' */
- socketSET_SOCKET_PORT( pxSocket, pxAddress->sin_port );
- /* And also store it in a socket field 'usLocalPort' in host-byte-order,
- * mostly used for logging and debugging purposes */
- pxSocket->usLocalPort = FreeRTOS_ntohs( pxAddress->sin_port );
- /* Add the socket to the list of bound ports. */
- {
- /* If the network driver can iterate through 'xBoundUDPSocketsList',
- * by calling xPortHasUDPSocket() then the IP-task must temporarily
- * suspend the scheduler to keep the list in a consistent state. */
- #if ( ipconfigETHERNET_DRIVER_FILTERS_PACKETS == 1 )
- {
- vTaskSuspendAll();
- }
- #endif /* ipconfigETHERNET_DRIVER_FILTERS_PACKETS */
- /* Add the socket to 'xBoundUDPSocketsList' or 'xBoundTCPSocketsList' */
- vListInsertEnd( pxSocketList, &( pxSocket->xBoundSocketListItem ) );
- #if ( ipconfigETHERNET_DRIVER_FILTERS_PACKETS == 1 )
- {
- ( void ) xTaskResumeAll();
- }
- #endif /* ipconfigETHERNET_DRIVER_FILTERS_PACKETS */
- }
- }
- } while( ipFALSE_BOOL );
- }
- #if ( ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND == 0 )
- else
- {
- xReturn = -pdFREERTOS_ERRNO_EADDRNOTAVAIL;
- FreeRTOS_debug_printf( ( "vSocketBind: Socket no addr\n" ) );
- }
- #endif
- if( xReturn != 0 )
- {
- iptraceBIND_FAILED( xSocket, ( FreeRTOS_ntohs( pxAddress->sin_port ) ) );
- }
- return xReturn;
- } /* Tested */
- /*-----------------------------------------------------------*/
- /**
- * @brief Close a socket and free the allocated space. In case of a TCP socket:
- * the connection will not be closed automatically. Subsequent messages
- * for the closed socket will be responded to with a RST. The IP-task
- * will actually close the socket, after receiving a 'eSocketCloseEvent'
- * message.
- *
- * @param[in] xSocket: the socket being closed.
- *
- * @return There are three distinct values which can be returned:
- * 0: If the xSocket is NULL/invalid.
- * 1: If the socket was successfully closed (read the brief above).
- * -1: If the socket was valid but could not be closed because the message
- * could not be delivered to the IP-task. Try again later.
- */
- BaseType_t FreeRTOS_closesocket( Socket_t xSocket )
- {
- BaseType_t xResult;
- #if ( ipconfigUSE_TCP == 1 ) && ( ipconfigUSE_CALLBACKS == 1 )
- FreeRTOS_Socket_t * pxSocket = ( FreeRTOS_Socket_t * ) xSocket;
- #endif
- IPStackEvent_t xCloseEvent;
- xCloseEvent.eEventType = eSocketCloseEvent;
- xCloseEvent.pvData = xSocket;
- if( ( xSocket == NULL ) || ( xSocket == FREERTOS_INVALID_SOCKET ) )
- {
- xResult = 0;
- }
- else
- {
- #if ( ( ipconfigUSE_TCP == 1 ) && ( ipconfigUSE_CALLBACKS == 1 ) )
- {
- if( pxSocket->ucProtocol == ( uint8_t ) FREERTOS_IPPROTO_TCP )
- {
- /* Make sure that IP-task won't call the user callback's anymore */
- pxSocket->u.xTCP.pxHandleConnected = NULL;
- pxSocket->u.xTCP.pxHandleReceive = NULL;
- pxSocket->u.xTCP.pxHandleSent = NULL;
- }
- }
- #endif /* ( ( ipconfigUSE_TCP == 1 ) && ( ipconfigUSE_CALLBACKS == 1 ) ) */
- /* Let the IP task close the socket to keep it synchronised with the
- * packet handling. */
- /* Note when changing the time-out value below, it must be checked who is calling
- * this function. If it is called by the IP-task, a deadlock could occur.
- * The IP-task would only call it in case of a user call-back */
- if( xSendEventStructToIPTask( &xCloseEvent, ( TickType_t ) 0 ) == pdFAIL )
- {
- FreeRTOS_debug_printf( ( "FreeRTOS_closesocket: failed\n" ) );
- xResult = -1;
- }
- else
- {
- xResult = 1;
- }
- }
- return xResult;
- }
- /**
- * @brief This is the internal version of FreeRTOS_closesocket(). It will
- * be called by the IPtask only to avoid problems with synchronicity.
- *
- * @param[in] pxSocket: The socket descriptor of the socket being closed.
- *
- * @return Returns NULL, always.
- */
- void * vSocketClose( FreeRTOS_Socket_t * pxSocket )
- {
- NetworkBufferDescriptor_t * pxNetworkBuffer;
- #if ( ipconfigUSE_TCP == 1 )
- {
- /* For TCP: clean up a little more. */
- if( pxSocket->ucProtocol == ( uint8_t ) FREERTOS_IPPROTO_TCP )
- {
- #if ( ipconfigUSE_TCP_WIN == 1 )
- {
- if( pxSocket->u.xTCP.pxAckMessage != NULL )
- {
- vReleaseNetworkBufferAndDescriptor( pxSocket->u.xTCP.pxAckMessage );
- }
- /* Free the resources which were claimed by the tcpWin member */
- vTCPWindowDestroy( &pxSocket->u.xTCP.xTCPWindow );
- }
- #endif /* ipconfigUSE_TCP_WIN */
- /* Free the input and output streams */
- if( pxSocket->u.xTCP.rxStream != NULL )
- {
- iptraceMEM_STATS_DELETE( pxSocket->u.xTCP.rxStream );
- vPortFreeLarge( pxSocket->u.xTCP.rxStream );
- }
- if( pxSocket->u.xTCP.txStream != NULL )
- {
- iptraceMEM_STATS_DELETE( pxSocket->u.xTCP.txStream );
- vPortFreeLarge( pxSocket->u.xTCP.txStream );
- }
- /* In case this is a child socket, make sure the child-count of the
- * parent socket is decreased. */
- prvTCPSetSocketCount( pxSocket );
- }
- }
- #endif /* ipconfigUSE_TCP == 1 */
- /* Socket must be unbound first, to ensure no more packets are queued on
- * it. */
- if( socketSOCKET_IS_BOUND( pxSocket ) )
- {
- /* If the network driver can iterate through 'xBoundUDPSocketsList',
- * by calling xPortHasUDPSocket(), then the IP-task must temporarily
- * suspend the scheduler to keep the list in a consistent state. */
- #if ( ipconfigETHERNET_DRIVER_FILTERS_PACKETS == 1 )
- {
- vTaskSuspendAll();
- }
- #endif /* ipconfigETHERNET_DRIVER_FILTERS_PACKETS */
- ( void ) uxListRemove( &( pxSocket->xBoundSocketListItem ) );
- #if ( ipconfigETHERNET_DRIVER_FILTERS_PACKETS == 1 )
- {
- ( void ) xTaskResumeAll();
- }
- #endif /* ipconfigETHERNET_DRIVER_FILTERS_PACKETS */
- }
- /* Now the socket is not bound the list of waiting packets can be
- * drained. */
- if( pxSocket->ucProtocol == ( uint8_t ) FREERTOS_IPPROTO_UDP )
- {
- while( listCURRENT_LIST_LENGTH( &( pxSocket->u.xUDP.xWaitingPacketsList ) ) > 0U )
- {
- pxNetworkBuffer = ipCAST_PTR_TO_TYPE_PTR( NetworkBufferDescriptor_t, listGET_OWNER_OF_HEAD_ENTRY( &( pxSocket->u.xUDP.xWaitingPacketsList ) ) );
- ( void ) uxListRemove( &( pxNetworkBuffer->xBufferListItem ) );
- vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );
- }
- }
- if( pxSocket->xEventGroup != NULL )
- {
- vEventGroupDelete( pxSocket->xEventGroup );
- }
- #if ( ipconfigUSE_TCP == 1 ) && ( ipconfigHAS_DEBUG_PRINTF != 0 )
- {
- if( pxSocket->ucProtocol == ( uint8_t ) FREERTOS_IPPROTO_TCP )
- {
- FreeRTOS_debug_printf( ( "FreeRTOS_closesocket[%u to %lxip:%u]: buffers %lu socks %lu\n",
- pxSocket->usLocalPort,
- pxSocket->u.xTCP.ulRemoteIP,
- pxSocket->u.xTCP.usRemotePort,
- uxGetNumberOfFreeNetworkBuffers(),
- listCURRENT_LIST_LENGTH( &xBoundTCPSocketsList ) ) );
- }
- }
- #endif /* ( ipconfigUSE_TCP == 1 ) && ( ipconfigHAS_DEBUG_PRINTF != 0 ) */
- /* And finally, after all resources have been freed, free the socket space */
- iptraceMEM_STATS_DELETE( pxSocket );
- vPortFreeSocket( pxSocket );
- return NULL;
- } /* Tested */
- /*-----------------------------------------------------------*/
- #if ipconfigUSE_TCP == 1
- /**
- * @brief When a child socket gets closed, make sure to update the child-count of the
- * parent. When a listening parent socket is closed, make sure no child-sockets
- * keep a pointer to it.
- *
- * @param[in] pxSocketToDelete: The socket being closed.
- */
- static void prvTCPSetSocketCount( FreeRTOS_Socket_t const * pxSocketToDelete )
- {
- const ListItem_t * pxIterator;
- const ListItem_t * pxEnd = listGET_END_MARKER( &xBoundTCPSocketsList );
- FreeRTOS_Socket_t * pxOtherSocket;
- uint16_t usLocalPort = pxSocketToDelete->usLocalPort;
- for( pxIterator = listGET_NEXT( pxEnd );
- pxIterator != pxEnd;
- pxIterator = listGET_NEXT( pxIterator ) )
- {
- pxOtherSocket = ipCAST_PTR_TO_TYPE_PTR( FreeRTOS_Socket_t, listGET_LIST_ITEM_OWNER( pxIterator ) );
- if( ( pxOtherSocket->u.xTCP.ucTCPState == ( uint8_t ) eTCP_LISTEN ) &&
- ( pxOtherSocket->usLocalPort == usLocalPort ) &&
- ( pxOtherSocket->u.xTCP.usChildCount != 0U ) )
- {
- pxOtherSocket->u.xTCP.usChildCount--;
- FreeRTOS_debug_printf( ( "Lost: Socket %u now has %u / %u child%s\n",
- pxOtherSocket->usLocalPort,
- pxOtherSocket->u.xTCP.usChildCount,
- pxOtherSocket->u.xTCP.usBacklog,
- ( pxOtherSocket->u.xTCP.usChildCount == 1U ) ? "" : "ren" ) );
- break;
- }
- }
- }
- #endif /* ipconfigUSE_TCP == 1 */
- /*-----------------------------------------------------------*/
- #if ( ipconfigUSE_TCP == 1 )
- /**
- * @brief Set the value of receive/send buffer after some preliminary checks.
- *
- * @param[in] pxSocket: The socket whose options are being set.
- * @param[in] lOptionName: The option name: either FREERTOS_SO_SNDBUF or
- * FREERTOS_SO_SNDBUF.
- * @param[in] pvOptionValue: The value of the option being set.
- *
- * @return If there is no error, then 0 is returned. Or a negative errno
- * value is returned.
- */
- static BaseType_t prvSockopt_so_buffer( FreeRTOS_Socket_t * pxSocket,
- int32_t lOptionName,
- const void * pvOptionValue )
- {
- uint32_t ulNewValue;
- BaseType_t xReturn;
- if( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_TCP )
- {
- FreeRTOS_debug_printf( ( "Set SO_%sBUF: wrong socket type\n",
- ( lOptionName == FREERTOS_SO_SNDBUF ) ? "SND" : "RCV" ) );
- xReturn = -pdFREERTOS_ERRNO_EINVAL;
- }
- else if( ( ( lOptionName == FREERTOS_SO_SNDBUF ) && ( pxSocket->u.xTCP.txStream != NULL ) ) ||
- ( ( lOptionName == FREERTOS_SO_RCVBUF ) && ( pxSocket->u.xTCP.rxStream != NULL ) ) )
- {
- FreeRTOS_debug_printf( ( "Set SO_%sBUF: buffer already created\n",
- ( lOptionName == FREERTOS_SO_SNDBUF ) ? "SND" : "RCV" ) );
- xReturn = -pdFREERTOS_ERRNO_EINVAL;
- }
- else
- {
- ulNewValue = *( ipPOINTER_CAST( const uint32_t *, pvOptionValue ) );
- if( lOptionName == FREERTOS_SO_SNDBUF )
- {
- /* Round up to nearest MSS size */
- ulNewValue = FreeRTOS_round_up( ulNewValue, ( uint32_t ) pxSocket->u.xTCP.usInitMSS );
- pxSocket->u.xTCP.uxTxStreamSize = ulNewValue;
- }
- else
- {
- pxSocket->u.xTCP.uxRxStreamSize = ulNewValue;
- }
- xReturn = 0;
- }
- return xReturn;
- }
- #endif /* ipconfigUSE_TCP == 1 */
- /*-----------------------------------------------------------*/
- /* FreeRTOS_setsockopt calls itself, but in a very limited way,
- * only when FREERTOS_SO_WIN_PROPERTIES is being set. */
- /**
- * @brief Set the socket options for the given socket.
- *
- * @param[in] xSocket: The socket for which the options are to be set.
- * @param[in] lLevel: Not used. Parameter is used to maintain the Berkeley sockets
- * standard.
- * @param[in] lOptionName: The name of the option to be set.
- * @param[in] pvOptionValue: The value of the option to be set.
- * @param[in] uxOptionLength: Not used. Parameter is used to maintain the Berkeley
- * sockets standard.
- *
- * @return If the option can be set with the given value, then 0 is returned. Else,
- * an error code is returned.
- */
- BaseType_t FreeRTOS_setsockopt( Socket_t xSocket,
- int32_t lLevel,
- int32_t lOptionName,
- const void * pvOptionValue,
- size_t uxOptionLength )
- {
- /* The standard Berkeley function returns 0 for success. */
- BaseType_t xReturn = -pdFREERTOS_ERRNO_EINVAL;
- FreeRTOS_Socket_t * pxSocket;
- pxSocket = ( FreeRTOS_Socket_t * ) xSocket;
- /* The function prototype is designed to maintain the expected Berkeley
- * sockets standard, but this implementation does not use all the parameters. */
- ( void ) lLevel;
- ( void ) uxOptionLength;
- if( ( pxSocket == NULL ) || ( pxSocket == FREERTOS_INVALID_SOCKET ) )
- {
- xReturn = -pdFREERTOS_ERRNO_EINVAL;
- return xReturn;
- }
- switch( lOptionName )
- {
- case FREERTOS_SO_RCVTIMEO:
- /* Receive time out. */
- pxSocket->xReceiveBlockTime = *( ( const TickType_t * ) pvOptionValue );
- xReturn = 0;
- break;
- case FREERTOS_SO_SNDTIMEO:
- pxSocket->xSendBlockTime = *( ( const TickType_t * ) pvOptionValue );
- if( pxSocket->ucProtocol == ( uint8_t ) FREERTOS_IPPROTO_UDP )
- {
- /* The send time out is capped for the reason stated in the
- * comments where ipconfigUDP_MAX_SEND_BLOCK_TIME_TICKS is defined
- * in FreeRTOSIPConfig.h (assuming an official configuration file
- * is being used. */
- if( pxSocket->xSendBlockTime > ipconfigUDP_MAX_SEND_BLOCK_TIME_TICKS )
- {
- pxSocket->xSendBlockTime = ipconfigUDP_MAX_SEND_BLOCK_TIME_TICKS;
- }
- }
- else
- {
- /* For TCP socket, it isn't necessary to limit the blocking time
- * because the FreeRTOS_send() function does not wait for a network
- * buffer to become available. */
- }
- xReturn = 0;
- break;
- #if ( ipconfigUDP_MAX_RX_PACKETS > 0U )
- case FREERTOS_SO_UDP_MAX_RX_PACKETS:
- if( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_UDP )
- {
- break; /* will return -pdFREERTOS_ERRNO_EINVAL */
- }
- pxSocket->u.xUDP.uxMaxPackets = *( ( const UBaseType_t * ) pvOptionValue );
- xReturn = 0;
- break;
- #endif /* ipconfigUDP_MAX_RX_PACKETS */
- case FREERTOS_SO_UDPCKSUM_OUT:
- /* Turn calculating of the UDP checksum on/off for this socket. If pvOptionValue
- * is anything else than NULL, the checksum generation will be turned on. */
- if( pvOptionValue == NULL )
- {
- pxSocket->ucSocketOptions &= ~( ( uint8_t ) FREERTOS_SO_UDPCKSUM_OUT );
- }
- else
- {
- pxSocket->ucSocketOptions |= ( uint8_t ) FREERTOS_SO_UDPCKSUM_OUT;
- }
- xReturn = 0;
- break;
- #if ( ipconfigUSE_CALLBACKS == 1 )
- #if ( ipconfigUSE_TCP == 1 )
- case FREERTOS_SO_TCP_CONN_HANDLER: /* Set a callback for (dis)connection events */
- case FREERTOS_SO_TCP_RECV_HANDLER: /* Install a callback for receiving TCP data. Supply pointer to 'F_TCP_UDP_Handler_t' (see below) */
- case FREERTOS_SO_TCP_SENT_HANDLER: /* Install a callback for sending TCP data. Supply pointer to 'F_TCP_UDP_Handler_t' (see below) */
- #endif /* ipconfigUSE_TCP */
- case FREERTOS_SO_UDP_RECV_HANDLER: /* Install a callback for receiving UDP data. Supply pointer to 'F_TCP_UDP_Handler_t' (see below) */
- case FREERTOS_SO_UDP_SENT_HANDLER: /* Install a callback for sending UDP data. Supply pointer to 'F_TCP_UDP_Handler_t' (see below) */
- {
- #if ( ipconfigUSE_TCP == 1 )
- {
- UBaseType_t uxProtocol;
- if( ( lOptionName == FREERTOS_SO_UDP_RECV_HANDLER ) ||
- ( lOptionName == FREERTOS_SO_UDP_SENT_HANDLER ) )
- {
- uxProtocol = ( UBaseType_t ) FREERTOS_IPPROTO_UDP;
- }
- else
- {
- uxProtocol = ( UBaseType_t ) FREERTOS_IPPROTO_TCP;
- }
- if( pxSocket->ucProtocol != ( uint8_t ) uxProtocol )
- {
- break; /* will return -pdFREERTOS_ERRNO_EINVAL */
- }
- }
- #else /* if ( ipconfigUSE_TCP == 1 ) */
- {
- /* No need to check if the socket has the right
- * protocol, because only UDP socket can be created. */
- }
- #endif /* ipconfigUSE_TCP */
- switch( lOptionName )
- {
- #if ipconfigUSE_TCP == 1
- case FREERTOS_SO_TCP_CONN_HANDLER:
- pxSocket->u.xTCP.pxHandleConnected = ipCAST_CONST_PTR_TO_CONST_TYPE_PTR( F_TCP_UDP_Handler_t, pvOptionValue )->pxOnTCPConnected;
- break;
- case FREERTOS_SO_TCP_RECV_HANDLER:
- pxSocket->u.xTCP.pxHandleReceive = ipCAST_CONST_PTR_TO_CONST_TYPE_PTR( F_TCP_UDP_Handler_t, pvOptionValue )->pxOnTCPReceive;
- break;
- case FREERTOS_SO_TCP_SENT_HANDLER:
- pxSocket->u.xTCP.pxHandleSent = ipCAST_CONST_PTR_TO_CONST_TYPE_PTR( F_TCP_UDP_Handler_t, pvOptionValue )->pxOnTCPSent;
- break;
- #endif /* ipconfigUSE_TCP */
- case FREERTOS_SO_UDP_RECV_HANDLER:
- pxSocket->u.xUDP.pxHandleReceive = ipCAST_CONST_PTR_TO_CONST_TYPE_PTR( F_TCP_UDP_Handler_t, pvOptionValue )->pxOnUDPReceive;
- break;
- case FREERTOS_SO_UDP_SENT_HANDLER:
- pxSocket->u.xUDP.pxHandleSent = ipCAST_CONST_PTR_TO_CONST_TYPE_PTR( F_TCP_UDP_Handler_t, pvOptionValue )->pxOnUDPSent;
- break;
- default:
- /* Should it throw an error here? */
- break;
- }
- }
- xReturn = 0;
- break;
- #endif /* ipconfigUSE_CALLBACKS */
- #if ( ipconfigUSE_TCP != 0 )
- #if ( ipconfigSOCKET_HAS_USER_SEMAPHORE != 0 )
- /* Each socket has a semaphore on which the using task normally
- * sleeps. */
- case FREERTOS_SO_SET_SEMAPHORE:
- {
- pxSocket->pxUserSemaphore = *( ipPOINTER_CAST( SemaphoreHandle_t *, pvOptionValue ) );
- }
- xReturn = 0;
- break;
- #endif /* ipconfigSOCKET_HAS_USER_SEMAPHORE */
- #if ( ipconfigSOCKET_HAS_USER_WAKE_CALLBACK != 0 )
- case FREERTOS_SO_WAKEUP_CALLBACK:
- /* Each socket can have a callback function that is executed
- * when there is an event the socket's owner might want to
- * process. */
- /* The type cast of the pointer expression "A" to type "B" removes const qualifier from the pointed to type. */
- pxSocket->pxUserWakeCallback = ( const SocketWakeupCallback_t ) pvOptionValue;
- xReturn = 0;
- break;
- #endif /* ipconfigSOCKET_HAS_USER_WAKE_CALLBACK */
- case FREERTOS_SO_SET_LOW_HIGH_WATER:
- {
- const LowHighWater_t * pxLowHighWater = ipPOINTER_CAST( const LowHighWater_t *, pvOptionValue );
- if( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_TCP )
- {
- /* It is not allowed to access 'pxSocket->u.xTCP'. */
- FreeRTOS_debug_printf( ( "FREERTOS_SO_SET_LOW_HIGH_WATER: wrong socket type\n" ) );
- break; /* will return -pdFREERTOS_ERRNO_EINVAL */
- }
- if( ( pxLowHighWater->uxLittleSpace >= pxLowHighWater->uxEnoughSpace ) ||
- ( pxLowHighWater->uxEnoughSpace > pxSocket->u.xTCP.uxRxStreamSize ) )
- {
- /* Impossible values. */
- FreeRTOS_debug_printf( ( "FREERTOS_SO_SET_LOW_HIGH_WATER: bad values\n" ) );
- break; /* will return -pdFREERTOS_ERRNO_EINVAL */
- }
- /* Send a STOP when buffer space drops below 'uxLittleSpace' bytes. */
- pxSocket->u.xTCP.uxLittleSpace = pxLowHighWater->uxLittleSpace;
- /* Send a GO when buffer space grows above 'uxEnoughSpace' bytes. */
- pxSocket->u.xTCP.uxEnoughSpace = pxLowHighWater->uxEnoughSpace;
- xReturn = 0;
- }
- break;
- case FREERTOS_SO_SNDBUF: /* Set the size of the send buffer, in units of MSS (TCP only) */
- case FREERTOS_SO_RCVBUF: /* Set the size of the receive buffer, in units of MSS (TCP only) */
- xReturn = prvSockopt_so_buffer( pxSocket, lOptionName, pvOptionValue );
- break;
- case FREERTOS_SO_WIN_PROPERTIES: /* Set all buffer and window properties in one call, parameter is pointer to WinProperties_t */
- {
- const WinProperties_t * pxProps;
- if( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_TCP )
- {
- FreeRTOS_debug_printf( ( "Set SO_WIN_PROP: wrong socket type\n" ) );
- break; /* will return -pdFREERTOS_ERRNO_EINVAL */
- }
- if( ( pxSocket->u.xTCP.txStream != NULL ) || ( pxSocket->u.xTCP.rxStream != NULL ) )
- {
- FreeRTOS_debug_printf( ( "Set SO_WIN_PROP: buffer already created\n" ) );
- break; /* will return -pdFREERTOS_ERRNO_EINVAL */
- }
- pxProps = ipPOINTER_CAST( const WinProperties_t *, pvOptionValue );
- xReturn = prvSockopt_so_buffer( pxSocket, FREERTOS_SO_SNDBUF, &( pxProps->lTxBufSize ) );
- if( xReturn != 0 )
- {
- break; /* will return an error. */
- }
- xReturn = prvSockopt_so_buffer( pxSocket, FREERTOS_SO_RCVBUF, &( pxProps->lRxBufSize ) );
- if( xReturn != 0 )
- {
- break; /* will return an error. */
- }
- #if ( ipconfigUSE_TCP_WIN == 1 )
- {
- pxSocket->u.xTCP.uxRxWinSize = ( uint32_t ) pxProps->lRxWinSize; /* Fixed value: size of the TCP reception window */
- pxSocket->u.xTCP.uxTxWinSize = ( uint32_t ) pxProps->lTxWinSize; /* Fixed value: size of the TCP transmit window */
- }
- #else
- {
- pxSocket->u.xTCP.uxRxWinSize = 1U;
- pxSocket->u.xTCP.uxTxWinSize = 1U;
- }
- #endif
- /* In case the socket has already initialised its tcpWin,
- * adapt the window size parameters */
- if( pxSocket->u.xTCP.xTCPWindow.u.bits.bHasInit != pdFALSE_UNSIGNED )
- {
- pxSocket->u.xTCP.xTCPWindow.xSize.ulRxWindowLength = pxSocket->u.xTCP.uxRxWinSize * pxSocket->u.xTCP.usInitMSS;
- pxSocket->u.xTCP.xTCPWindow.xSize.ulTxWindowLength = pxSocket->u.xTCP.uxTxWinSize * pxSocket->u.xTCP.usInitMSS;
- }
- }
- xReturn = 0;
- break;
- case FREERTOS_SO_REUSE_LISTEN_SOCKET: /* If true, the server-socket will turn into a connected socket */
- {
- if( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_TCP )
- {
- break; /* will return -pdFREERTOS_ERRNO_EINVAL */
- }
- if( *( ( const BaseType_t * ) pvOptionValue ) != 0 )
- {
- pxSocket->u.xTCP.bits.bReuseSocket = pdTRUE;
- }
- else
- {
- pxSocket->u.xTCP.bits.bReuseSocket = pdFALSE;
- }
- }
- xReturn = 0;
- break;
- case FREERTOS_SO_CLOSE_AFTER_SEND: /* As soon as the last byte has been transmitted, finalise the connection */
- {
- if( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_TCP )
- {
- break; /* will return -pdFREERTOS_ERRNO_EINVAL */
- }
- if( *( ( const BaseType_t * ) pvOptionValue ) != 0 )
- {
- pxSocket->u.xTCP.bits.bCloseAfterSend = pdTRUE;
- }
- else
- {
- pxSocket->u.xTCP.bits.bCloseAfterSend = pdFALSE;
- }
- }
- xReturn = 0;
- break;
- case FREERTOS_SO_SET_FULL_SIZE: /* Refuse to send packets smaller than MSS */
- {
- if( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_TCP )
- {
- break; /* will return -pdFREERTOS_ERRNO_EINVAL */
- }
- if( *( ( const BaseType_t * ) pvOptionValue ) != 0 )
- {
- pxSocket->u.xTCP.xTCPWindow.u.bits.bSendFullSize = pdTRUE;
- }
- else
- {
- pxSocket->u.xTCP.xTCPWindow.u.bits.bSendFullSize = pdFALSE;
- }
- if( ( pxSocket->u.xTCP.xTCPWindow.u.bits.bSendFullSize == pdFALSE_UNSIGNED ) &&
- ( pxSocket->u.xTCP.ucTCPState >= ( uint8_t ) eESTABLISHED ) &&
- ( FreeRTOS_outstanding( pxSocket ) != 0 ) )
- {
- pxSocket->u.xTCP.usTimeout = 1U; /* to set/clear bSendFullSize */
- ( void ) xSendEventToIPTask( eTCPTimerEvent );
- }
- }
- xReturn = 0;
- break;
- case FREERTOS_SO_STOP_RX: /* Refuse to receive more packets. */
- {
- if( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_TCP )
- {
- break; /* will return -pdFREERTOS_ERRNO_EINVAL */
- }
- if( *( ( const BaseType_t * ) pvOptionValue ) != 0 )
- {
- pxSocket->u.xTCP.bits.bRxStopped = pdTRUE;
- }
- else
- {
- pxSocket->u.xTCP.bits.bRxStopped = pdFALSE;
- }
- pxSocket->u.xTCP.bits.bWinChange = pdTRUE;
- pxSocket->u.xTCP.usTimeout = 1U; /* to set/clear bRxStopped */
- ( void ) xSendEventToIPTask( eTCPTimerEvent );
- }
- xReturn = 0;
- break;
- #endif /* ipconfigUSE_TCP == 1 */
- default:
- /* No other options are handled. */
- xReturn = -pdFREERTOS_ERRNO_ENOPROTOOPT;
- break;
- }
- return xReturn;
- } /* Tested */
- /*-----------------------------------------------------------*/
- /**
- * @brief Find an available port number per https://tools.ietf.org/html/rfc6056.
- *
- * @param[in] xProtocol: FREERTOS_IPPROTO_TCP/FREERTOS_IPPROTO_UDP.
- *
- * @return If an available protocol port is found then that port number is returned.
- * Or else, 0 is returned.
- */
- static uint16_t prvGetPrivatePortNumber( BaseType_t xProtocol )
- {
- const uint16_t usEphemeralPortCount =
- socketAUTO_PORT_ALLOCATION_MAX_NUMBER - ( socketAUTO_PORT_ALLOCATION_START_NUMBER - 1U );
- uint16_t usIterations = usEphemeralPortCount;
- uint32_t ulRandomSeed = 0;
- uint16_t usResult = 0;
- const List_t * pxList;
- #if ipconfigUSE_TCP == 1
- if( xProtocol == ( BaseType_t ) FREERTOS_IPPROTO_TCP )
- {
- pxList = &xBoundTCPSocketsList;
- }
- else
- #endif
- {
- pxList = &xBoundUDPSocketsList;
- }
- /* Avoid compiler warnings if ipconfigUSE_TCP is not defined. */
- ( void ) xProtocol;
- /* Find the next available port using the random seed as a starting
- * point. */
- do
- {
- /* Only proceed if the random number generator succeeded. */
- if( xApplicationGetRandomNumber( &( ulRandomSeed ) ) == pdFALSE )
- {
- break;
- }
- /* Map the random to a candidate port. */
- usResult =
- socketAUTO_PORT_ALLOCATION_START_NUMBER +
- ( ( ( uint16_t ) ulRandomSeed ) % usEphemeralPortCount );
- /* Check if there's already an open socket with the same protocol
- * and port. */
- if( NULL == pxListFindListItemWithValue(
- pxList,
- ( TickType_t ) FreeRTOS_htons( usResult ) ) )
- {
- usResult = FreeRTOS_htons( usResult );
- break;
- }
- else
- {
- usResult = 0;
- }
- usIterations--;
- }
- while( usIterations > 0U );
- return usResult;
- }
- /*-----------------------------------------------------------*/
- /**
- * @brief Find a list item associated with the wanted-item.
- *
- * @param[in] pxList: The list through which the search is to be conducted.
- * @param[in] xWantedItemValue: The wanted item whose association is to be found.
- *
- * @return The list item holding the value being searched for. If nothing is found,
- * then a NULL is returned.
- */
- static const ListItem_t * pxListFindListItemWithValue( const List_t * pxList,
- TickType_t xWantedItemValue )
- {
- const ListItem_t * pxResult = NULL;
- if( ( xIPIsNetworkTaskReady() != pdFALSE ) && ( pxList != NULL ) )
- {
- const ListItem_t * pxIterator;
- const ListItem_t * pxEnd = listGET_END_MARKER( pxList );
- for( pxIterator = listGET_NEXT( pxEnd );
- pxIterator != pxEnd;
- pxIterator = listGET_NEXT( pxIterator ) )
- {
- if( listGET_LIST_ITEM_VALUE( pxIterator ) == xWantedItemValue )
- {
- pxResult = pxIterator;
- break;
- }
- }
- }
- return pxResult;
- } /* Tested */
- /*-----------------------------------------------------------*/
- /**
- * @brief Find the UDP socket corresponding to the port number.
- *
- * @param[in] uxLocalPort: The port whose corresponding bound UDP socket
- * is to be found.
- *
- * @return The socket owning the port if found or else NULL.
- */
- FreeRTOS_Socket_t * pxUDPSocketLookup( UBaseType_t uxLocalPort )
- {
- const ListItem_t * pxListItem;
- FreeRTOS_Socket_t * pxSocket = NULL;
- /* Looking up a socket is quite simple, find a match with the local port.
- *
- * See if there is a list item associated with the port number on the
- * list of bound sockets. */
- pxListItem = pxListFindListItemWithValue( &xBoundUDPSocketsList, ( TickType_t ) uxLocalPort );
- if( pxListItem != NULL )
- {
- /* The owner of the list item is the socket itself. */
- pxSocket = ipCAST_PTR_TO_TYPE_PTR( FreeRTOS_Socket_t, listGET_LIST_ITEM_OWNER( pxListItem ) );
- configASSERT( pxSocket != NULL );
- }
- return pxSocket;
- }
- /*-----------------------------------------------------------*/
- #define sockDIGIT_COUNT ( 3U ) /**< Each nibble is expressed in at most 3 digits such as "192". */
- /**
- * @brief Convert the 32-bit representation of the IP-address to the dotted decimal
- * notation after some checks.
- * A safe alternative is FreeRTOS_inet_ntop4().
- *
- * @param[in] ulIPAddress: 32-bit representation of the IP-address.
- * @param[out] pcBuffer: The buffer where the dotted decimal representation will be
- * stored if all checks pass. The buffer must be at least 16
- * bytes long.
- *
- * @return If all checks pass, then the pointer returned will be same as pcBuffer
- * and will have the address stored in the location. Else, NULL is returned.
- */
- const char * FreeRTOS_inet_ntoa( uint32_t ulIPAddress,
- char * pcBuffer )
- {
- socklen_t uxNibble;
- socklen_t uxIndex = 0;
- const uint8_t * pucAddress = ( const uint8_t * ) &( ulIPAddress );
- const char * pcResult = pcBuffer;
- const socklen_t uxSize = 16;
- for( uxNibble = 0; uxNibble < ipSIZE_OF_IPv4_ADDRESS; uxNibble++ )
- {
- uint8_t pucDigits[ sockDIGIT_COUNT ];
- uint8_t ucValue = pucAddress[ uxNibble ];
- socklen_t uxSource = ( socklen_t ) sockDIGIT_COUNT - ( socklen_t ) 1U;
- socklen_t uxNeeded;
- for( ; ; )
- {
- pucDigits[ uxSource ] = ucValue % ( uint8_t ) 10U;
- ucValue /= ( uint8_t ) 10U;
- if( uxSource == 1U )
- {
- break;
- }
- uxSource--;
- }
- pucDigits[ 0 ] = ucValue;
- /* Skip leading zeros. */
- for( uxSource = 0; uxSource < ( ( socklen_t ) sockDIGIT_COUNT - ( socklen_t ) 1U ); uxSource++ )
- {
- if( pucDigits[ uxSource ] != 0U )
- {
- break;
- }
- }
- /* Write e.g. "192.", which is 3 digits and a dot. */
- uxNeeded = ( ( socklen_t ) sockDIGIT_COUNT - uxSource ) + 1U;
- if( ( uxIndex + uxNeeded ) > uxSize )
- {
- /* The result won't fit. */
- pcResult = NULL;
- break;
- }
- for( ; uxSource < ( socklen_t ) sockDIGIT_COUNT; uxSource++ )
- {
- pcBuffer[ uxIndex ] = ( char ) ( pucDigits[ uxSource ] + ( char ) '0' );
- uxIndex++;
- }
- if( uxNibble < ( ipSIZE_OF_IPv4_ADDRESS - 1U ) )
- {
- pcBuffer[ uxIndex ] = '.';
- }
- else
- {
- pcBuffer[ uxIndex ] = '\0';
- }
- uxIndex++;
- }
- return pcResult;
- }
- /*-----------------------------------------------------------*/
- /**
- * @brief Convert the dotted decimal format of the IP-address to the 32-bit representation.
- *
- * @param[in] xAddressFamily: The Address family to which the IP-address belongs to. Only
- * FREERTOS_AF_INET (IPv4) is supported.
- * @param[in] pcSource: Pointer to the string holding the dotted decimal representation of
- * the IP-address.
- * @param[out] pvDestination: The pointer to the address struct/variable where the converted
- * IP-address will be stored. The buffer must be 4 bytes long
- * in case of a IPv4 address.
- *
- * @return If all checks pass, then pdPASS is returned or else pdFAIL is returned.
- */
- BaseType_t FreeRTOS_inet_pton( BaseType_t xAddressFamily,
- const char * pcSource,
- void * pvDestination )
- {
- BaseType_t xResult;
- /* Printable string to struct sockaddr. */
- switch( xAddressFamily )
- {
- case FREERTOS_AF_INET:
- xResult = FreeRTOS_inet_pton4( pcSource, pvDestination );
- break;
- default:
- xResult = -pdFREERTOS_ERRNO_EAFNOSUPPORT;
- break;
- }
- return xResult;
- }
- /*-----------------------------------------------------------*/
- /**
- * @brief Convert the 32-bit representation of the IP-address to the dotted
- * decimal format based on the Address Family. (Only FREERTOS_AF_INET
- * is allowed).
- *
- * @param[in] xAddressFamily: The address family of the IP-address.
- * @param[in] pvSource: Pointer to the 32-bit representation of IP-address.
- * @param[out] pcDestination: The pointer to the character array where the dotted
- * decimal address will be stored if every check does pass.
- * @param[in] uxSize: Size of the character array. This value makes sure that the code
- * doesn't write beyond it's bounds.
- *
- * @return If every check does pass, then the pointer to the pcDestination is returned
- * holding the dotted decimal format of IP-address. Else, a NULL is returned.
- */
- const char * FreeRTOS_inet_ntop( BaseType_t xAddressFamily,
- const void * pvSource,
- char * pcDestination,
- socklen_t uxSize )
- {
- const char * pcResult;
- /* Printable struct sockaddr to string. */
- switch( xAddressFamily )
- {
- case FREERTOS_AF_INET:
- pcResult = FreeRTOS_inet_ntop4( pvSource, pcDestination, uxSize );
- break;
- default:
- /* errno should be set to pdFREERTOS_ERRNO_EAFNOSUPPORT. */
- pcResult = NULL;
- break;
- }
- return pcResult;
- }
- /*-----------------------------------------------------------*/
- /**
- * @brief Convert the 32-bit representation of the IP-address to the dotted decimal format.
- *
- * @param[in] pvSource: The pointer to the 32-bit representation of the IP-address.
- * @param[out] pcDestination: The pointer to a character array where the string of the
- * dotted decimal IP format.
- * @param[in] uxSize: Size of the character array. This value makes sure that the code
- * doesn't write beyond it's bounds.
- *
- * @return The pointer to the string holding the dotted decimal format of the IP-address. If
- * everything passes correctly, then the pointer being returned is the same as
- * pcDestination, else a NULL is returned.
- */
- const char * FreeRTOS_inet_ntop4( const void * pvSource,
- char * pcDestination,
- socklen_t uxSize )
- {
- uint32_t ulIPAddress;
- void * pvCopyDest;
- const char * pcReturn;
- if( uxSize < 16U )
- {
- /* There must be space for "255.255.255.255". */
- pcReturn = NULL;
- }
- else
- {
- pvCopyDest = ( void * ) &ulIPAddress;
- ( void ) memcpy( pvCopyDest, pvSource, sizeof( ulIPAddress ) );
- ( void ) FreeRTOS_inet_ntoa( ulIPAddress, pcDestination );
- pcReturn = pcDestination;
- }
- return pcReturn;
- }
- /*-----------------------------------------------------------*/
- /**
- * @brief This function converts the character string pcSource into a network address
- * structure, then copies the network address structure to pvDestination.
- * pvDestination is written in network byte order.
- *
- * @param[in] pcSource: The character string in holding the IP address.
- * @param[out] pvDestination: The returned network address in 32-bit network-endian format.
- *
- * @return pdPASS if the translation was successful or else pdFAIL.
- */
- BaseType_t FreeRTOS_inet_pton4( const char * pcSource,
- void * pvDestination )
- {
- const uint32_t ulDecimalBase = 10U;
- uint8_t ucOctet[ socketMAX_IP_ADDRESS_OCTETS ];
- uint32_t ulReturn = 0UL, ulValue;
- UBaseType_t uxOctetNumber;
- BaseType_t xResult = pdPASS;
- const char * pcIPAddress = pcSource;
- const void * pvCopySource;
- ( void ) memset( pvDestination, 0, sizeof( ulReturn ) );
- /* Translate "192.168.2.100" to a 32-bit number, network-endian. */
- for( uxOctetNumber = 0U; uxOctetNumber < socketMAX_IP_ADDRESS_OCTETS; uxOctetNumber++ )
- {
- ulValue = 0UL;
- if( pcIPAddress[ 0 ] == '0' )
- {
- /* Test for the sequence "0[0-9]", which would make it an octal representation. */
- if( ( pcIPAddress[ 1 ] >= '0' ) && ( pcIPAddress[ 1 ] <= '9' ) )
- {
- FreeRTOS_printf( ( "Octal representation of IP-addresses is not supported." ) );
- /* Don't support octal numbers. */
- xResult = pdFAIL;
- break;
- }
- }
- while( ( *pcIPAddress >= '0' ) && ( *pcIPAddress <= '9' ) )
- {
- BaseType_t xChar;
- /* Move previous read characters into the next decimal
- * position. */
- ulValue *= ulDecimalBase;
- /* Add the binary value of the ascii character. */
- xChar = ( BaseType_t ) pcIPAddress[ 0 ];
- xChar = xChar - ( BaseType_t ) '0';
- ulValue += ( uint32_t ) xChar;
- /* Move to next character in the string. */
- pcIPAddress++;
- }
- /* Check characters were read. */
- if( pcIPAddress == pcSource )
- {
- xResult = pdFAIL;
- }
- /* Check the value fits in an 8-bit number. */
- if( ulValue > 0xffUL )
- {
- xResult = pdFAIL;
- }
- else
- {
- ucOctet[ uxOctetNumber ] = ( uint8_t ) ulValue;
- /* Check the next character is as expected. */
- if( uxOctetNumber < ( socketMAX_IP_ADDRESS_OCTETS - 1U ) )
- {
- if( *pcIPAddress != '.' )
- {
- xResult = pdFAIL;
- }
- else
- {
- /* Move past the dot. */
- pcIPAddress++;
- }
- }
- }
- if( xResult == pdFAIL )
- {
- /* No point going on. */
- break;
- }
- }
- if( *pcIPAddress != ( char ) 0 )
- {
- /* Expected the end of the string. */
- xResult = pdFAIL;
- }
- if( uxOctetNumber != socketMAX_IP_ADDRESS_OCTETS )
- {
- /* Didn't read enough octets. */
- xResult = pdFAIL;
- }
- if( xResult == pdPASS )
- {
- /* lint: ucOctet has been set because xResult == pdPASS. */
- ulReturn = FreeRTOS_inet_addr_quick( ucOctet[ 0 ], ucOctet[ 1 ], ucOctet[ 2 ], ucOctet[ 3 ] );
- }
- else
- {
- ulReturn = 0UL;
- }
- if( xResult == pdPASS )
- {
- pvCopySource = ( const void * ) &ulReturn;
- ( void ) memcpy( pvDestination, pvCopySource, sizeof( ulReturn ) );
- }
- return xResult;
- }
- /*-----------------------------------------------------------*/
- /**
- * @brief Convert the IP address from "w.x.y.z" (dotted decimal) format to the 32-bit format.
- *
- * @param[in] pcIPAddress: The character string pointer holding the IP-address in the "W.X.Y.Z"
- * (dotted decimal) format.
- *
- * @return The 32-bit representation of IP(v4) address.
- */
- uint32_t FreeRTOS_inet_addr( const char * pcIPAddress )
- {
- uint32_t ulReturn = 0UL;
- /* inet_pton AF_INET target is a 4-byte 'struct in_addr'. */
- ( void ) FreeRTOS_inet_pton4( pcIPAddress, &( ulReturn ) );
- return ulReturn;
- }
- /*-----------------------------------------------------------*/
- /**
- * @brief Function to get the local address and IP port of the given socket.
- *
- * @param[in] xSocket: Socket whose port is to be added to the pxAddress.
- * @param[out] pxAddress: Structure in which the IP address and the port number
- * is returned.
- *
- * @return Size of the freertos_sockaddr structure.
- */
- size_t FreeRTOS_GetLocalAddress( ConstSocket_t xSocket,
- struct freertos_sockaddr * pxAddress )
- {
- const FreeRTOS_Socket_t * pxSocket = ( const FreeRTOS_Socket_t * ) xSocket;
- /* IP address of local machine. */
- pxAddress->sin_addr = *ipLOCAL_IP_ADDRESS_POINTER;
- /* Local port on this machine. */
- pxAddress->sin_port = FreeRTOS_htons( pxSocket->usLocalPort );
- return sizeof( *pxAddress );
- }
- /*-----------------------------------------------------------*/
- /**
- * @brief Wake up the user of the given socket through event-groups.
- *
- * @param[in] pxSocket: The socket whose user is to be woken up.
- */
- void vSocketWakeUpUser( FreeRTOS_Socket_t * pxSocket )
- {
- /* _HT_ must work this out, now vSocketWakeUpUser will be called for any important
- * event or transition */
- #if ( ipconfigSOCKET_HAS_USER_SEMAPHORE == 1 )
- {
- if( pxSocket->pxUserSemaphore != NULL )
- {
- ( void ) xSemaphoreGive( pxSocket->pxUserSemaphore );
- }
- }
- #endif /* ipconfigSOCKET_HAS_USER_SEMAPHORE */
- #if ( ipconfigSOCKET_HAS_USER_WAKE_CALLBACK == 1 )
- {
- if( pxSocket->pxUserWakeCallback != NULL )
- {
- pxSocket->pxUserWakeCallback( pxSocket );
- }
- }
- #endif /* ipconfigSOCKET_HAS_USER_WAKE_CALLBACK */
- #if ( ipconfigSUPPORT_SELECT_FUNCTION == 1 )
- {
- if( pxSocket->pxSocketSet != NULL )
- {
- EventBits_t xSelectBits = ( pxSocket->xEventBits >> SOCKET_EVENT_BIT_COUNT ) & ( ( EventBits_t ) eSELECT_ALL );
- if( xSelectBits != 0UL )
- {
- pxSocket->xSocketBits |= xSelectBits;
- ( void ) xEventGroupSetBits( pxSocket->pxSocketSet->xSelectGroup, xSelectBits );
- }
- }
- pxSocket->xEventBits &= ( EventBits_t ) eSOCKET_ALL;
- }
- #endif /* ipconfigSUPPORT_SELECT_FUNCTION */
- if( ( pxSocket->xEventGroup != NULL ) && ( pxSocket->xEventBits != 0U ) )
- {
- ( void ) xEventGroupSetBits( pxSocket->xEventGroup, pxSocket->xEventBits );
- }
- pxSocket->xEventBits = 0UL;
- }
- /*-----------------------------------------------------------*/
- #if ( ipconfigETHERNET_DRIVER_FILTERS_PACKETS == 1 )
- /**
- * @brief This define makes it possible for network interfaces to inspect
- * UDP messages and see if there is any UDP socket bound to a given port
- * number. This is probably only useful in systems with a minimum of
- * RAM and when lots of anonymous broadcast messages come in.
- *
- * @param[in] usPortNr: the port number to look for.
- *
- * @return xFound if a socket with the port number is found.
- */
- BaseType_t xPortHasUDPSocket( uint16_t usPortNr )
- {
- BaseType_t xFound = pdFALSE;
- vTaskSuspendAll();
- {
- if( ( pxListFindListItemWithValue( &xBoundUDPSocketsList, ( TickType_t ) usPortNr ) != NULL ) )
- {
- xFound = pdTRUE;
- }
- }
- ( void ) xTaskResumeAll();
- return xFound;
- }
- #endif /* ipconfigETHERNET_DRIVER_FILTERS_PACKETS */
- /*-----------------------------------------------------------*/
- #if ( ipconfigUSE_TCP == 1 )
- /**
- * @brief Check if it makes any sense to wait for a connect event.
- *
- * @param[in] pxSocket: The socket trying to connect.
- *
- * @return It may return: -EINPROGRESS, -EAGAIN, or 0 for OK.
- */
- static BaseType_t bMayConnect( FreeRTOS_Socket_t const * pxSocket )
- {
- BaseType_t xResult;
- eIPTCPState_t eState = ipNUMERIC_CAST( eIPTCPState_t, pxSocket->u.xTCP.ucTCPState );
- switch( eState )
- {
- case eCLOSED:
- case eCLOSE_WAIT:
- xResult = 0;
- break;
- case eCONNECT_SYN:
- xResult = -pdFREERTOS_ERRNO_EINPROGRESS;
- break;
- case eTCP_LISTEN:
- case eSYN_FIRST:
- case eSYN_RECEIVED:
- case eESTABLISHED:
- case eFIN_WAIT_1:
- case eFIN_WAIT_2:
- case eCLOSING:
- case eLAST_ACK:
- case eTIME_WAIT:
- default:
- xResult = -pdFREERTOS_ERRNO_EAGAIN;
- break;
- }
- return xResult;
- }
- #endif /* ipconfigUSE_TCP */
- /*-----------------------------------------------------------*/
- #if ( ipconfigUSE_TCP == 1 )
- /**
- * @brief Called from #FreeRTOS_connect(): make some checks and if allowed,
- * send a message to the IP-task to start connecting to a remote socket.
- *
- * @param[in] pxSocket: The socket attempting to connect to a remote port.
- * @param[in] pxAddress: The address the socket is trying to connect to.
- *
- * @return 0 on successful checks or a negative error code.
- */
- static BaseType_t prvTCPConnectStart( FreeRTOS_Socket_t * pxSocket,
- struct freertos_sockaddr const * pxAddress )
- {
- BaseType_t xResult = 0;
- if( pxAddress == NULL )
- {
- /* NULL address passed to the function. Invalid value. */
- xResult = -pdFREERTOS_ERRNO_EINVAL;
- }
- else if( prvValidSocket( pxSocket, FREERTOS_IPPROTO_TCP, pdFALSE ) == pdFALSE )
- {
- /* Not a valid socket or wrong type */
- xResult = -pdFREERTOS_ERRNO_EBADF;
- }
- else if( FreeRTOS_issocketconnected( pxSocket ) > 0 )
- {
- /* The socket is already connected. */
- xResult = -pdFREERTOS_ERRNO_EISCONN;
- }
- else if( !socketSOCKET_IS_BOUND( pxSocket ) )
- {
- /* Bind the socket to the port that the client task will send from.
- * Non-standard, so the error returned is that returned by bind(). */
- xResult = FreeRTOS_bind( pxSocket, NULL, 0U );
- }
- else
- {
- /* The socket is valid, not yet connected, and already bound to a port number. */
- }
- if( xResult == 0 )
- {
- /* Check if it makes any sense to wait for a connect event, this condition
- * might change while sleeping, so it must be checked within each loop */
- xResult = bMayConnect( pxSocket ); /* -EINPROGRESS, -EAGAIN, or 0 for OK */
- /* Start the connect procedure, kernel will start working on it */
- if( xResult == 0 )
- {
- pxSocket->u.xTCP.bits.bConnPrepared = pdFALSE;
- pxSocket->u.xTCP.ucRepCount = 0U;
- FreeRTOS_debug_printf( ( "FreeRTOS_connect: %u to %lxip:%u\n",
- pxSocket->usLocalPort, FreeRTOS_ntohl( pxAddress->sin_addr ), FreeRTOS_ntohs( pxAddress->sin_port ) ) );
- /* Port on remote machine. */
- pxSocket->u.xTCP.usRemotePort = FreeRTOS_ntohs( pxAddress->sin_port );
- /* IP address of remote machine. */
- pxSocket->u.xTCP.ulRemoteIP = FreeRTOS_ntohl( pxAddress->sin_addr );
- /* (client) internal state: socket wants to send a connect. */
- vTCPStateChange( pxSocket, eCONNECT_SYN );
- /* To start an active connect. */
- pxSocket->u.xTCP.usTimeout = 1U;
- if( xSendEventToIPTask( eTCPTimerEvent ) != pdPASS )
- {
- xResult = -pdFREERTOS_ERRNO_ECANCELED;
- }
- }
- }
- return xResult;
- }
- #endif /* ipconfigUSE_TCP */
- /*-----------------------------------------------------------*/
- #if ( ipconfigUSE_TCP == 1 )
- /**
- * @brief Connect to a remote port.
- *
- * @param[in] xClientSocket: The socket initiating the connection.
- * @param[in] pxAddress: The address of the remote socket.
- * @param[in] xAddressLength: This parameter is not used. It is kept in
- * the function signature to adhere to the Berkeley
- * sockets standard.
- *
- * @return 0 is returned on a successful connection, else a negative
- * error code is returned.
- */
- BaseType_t FreeRTOS_connect( Socket_t xClientSocket,
- struct freertos_sockaddr * pxAddress,
- socklen_t xAddressLength )
- {
- FreeRTOS_Socket_t * pxSocket = ( FreeRTOS_Socket_t * ) xClientSocket;
- TickType_t xRemainingTime;
- BaseType_t xTimed = pdFALSE;
- BaseType_t xResult = -pdFREERTOS_ERRNO_EINVAL;
- TimeOut_t xTimeOut;
- ( void ) xAddressLength;
- xResult = prvTCPConnectStart( pxSocket, pxAddress );
- if( xResult == 0 )
- {
- /* And wait for the result */
- for( ; ; )
- {
- if( xTimed == pdFALSE )
- {
- /* Only in the first round, check for non-blocking */
- xRemainingTime = pxSocket->xReceiveBlockTime;
- if( xRemainingTime == ( TickType_t ) 0 )
- {
- /* Not yet connected, correct state, non-blocking. */
- xResult = -pdFREERTOS_ERRNO_EWOULDBLOCK;
- break;
- }
- /* Don't get here a second time. */
- xTimed = pdTRUE;
- /* Fetch the current time */
- vTaskSetTimeOutState( &xTimeOut );
- }
- /* Did it get connected while sleeping ? */
- xResult = FreeRTOS_issocketconnected( pxSocket );
- /* Returns positive when connected, negative means an error */
- if( xResult < 0 )
- {
- /* Return the error */
- break;
- }
- if( xResult > 0 )
- {
- /* Socket now connected, return a zero */
- xResult = 0;
- break;
- }
- /* Is it allowed to sleep more? */
- if( xTaskCheckForTimeOut( &xTimeOut, &xRemainingTime ) != pdFALSE )
- {
- xResult = -pdFREERTOS_ERRNO_ETIMEDOUT;
- break;
- }
- /* Go sleeping until we get any down-stream event */
- ( void ) xEventGroupWaitBits( pxSocket->xEventGroup, ( EventBits_t ) eSOCKET_CONNECT, pdTRUE /*xClearOnExit*/, pdFALSE /*xWaitAllBits*/, xRemainingTime );
- }
- }
- return xResult;
- }
- #endif /* ipconfigUSE_TCP */
- /*-----------------------------------------------------------*/
- #if ( ipconfigUSE_TCP == 1 )
- /**
- * @brief Accept a connection on an listening socket.
- *
- * @param[in] xServerSocket: The socket in listening mode.
- * @param[out] pxAddress: The address of the machine trying to connect to this node
- * is returned in this pointer.
- * @param[out] pxAddressLength: The length of the address of the remote machine.
- *
- * @return FreeRTOS_accept: can return a new connected socket if the server socket
- * is in listen mode and receives a connection request. The new socket will
- * be bound already to the same port number as the listening socket.
- */
- Socket_t FreeRTOS_accept( Socket_t xServerSocket,
- struct freertos_sockaddr * pxAddress,
- socklen_t * pxAddressLength )
- {
- FreeRTOS_Socket_t * pxSocket = ( FreeRTOS_Socket_t * ) xServerSocket;
- FreeRTOS_Socket_t * pxClientSocket = NULL;
- TickType_t xRemainingTime;
- BaseType_t xTimed = pdFALSE, xAsk = pdFALSE;
- TimeOut_t xTimeOut;
- IPStackEvent_t xAskEvent;
- if( prvValidSocket( pxSocket, FREERTOS_IPPROTO_TCP, pdTRUE ) == pdFALSE )
- {
- /* Not a valid socket or wrong type */
- pxClientSocket = FREERTOS_INVALID_SOCKET;
- }
- else if( ( pxSocket->u.xTCP.bits.bReuseSocket == pdFALSE_UNSIGNED ) &&
- ( pxSocket->u.xTCP.ucTCPState != ( uint8_t ) eTCP_LISTEN ) )
- {
- /* Parent socket is not in listening mode */
- pxClientSocket = FREERTOS_INVALID_SOCKET;
- }
- else
- {
- /* Loop will stop with breaks. */
- for( ; ; )
- {
- /* Is there a new client? */
- vTaskSuspendAll();
- {
- if( pxSocket->u.xTCP.bits.bReuseSocket == pdFALSE_UNSIGNED )
- {
- pxClientSocket = pxSocket->u.xTCP.pxPeerSocket;
- }
- else
- {
- pxClientSocket = pxSocket;
- }
- if( pxClientSocket != NULL )
- {
- pxSocket->u.xTCP.pxPeerSocket = NULL;
- /* Is it still not taken ? */
- if( pxClientSocket->u.xTCP.bits.bPassAccept != pdFALSE_UNSIGNED )
- {
- pxClientSocket->u.xTCP.bits.bPassAccept = pdFALSE;
- }
- else
- {
- pxClientSocket = NULL;
- }
- }
- }
- ( void ) xTaskResumeAll();
- if( pxClientSocket != NULL )
- {
- if( pxAddress != NULL )
- {
- /* IP address of remote machine. */
- pxAddress->sin_addr = FreeRTOS_ntohl( pxClientSocket->u.xTCP.ulRemoteIP );
- /* Port on remote machine. */
- pxAddress->sin_port = FreeRTOS_ntohs( pxClientSocket->u.xTCP.usRemotePort );
- }
- if( pxAddressLength != NULL )
- {
- *pxAddressLength = sizeof( *pxAddress );
- }
- if( pxSocket->u.xTCP.bits.bReuseSocket == pdFALSE_UNSIGNED )
- {
- xAsk = pdTRUE;
- }
- }
- if( xAsk != pdFALSE )
- {
- /* Ask to set an event in 'xEventGroup' as soon as a new
- * client gets connected for this listening socket. */
- xAskEvent.eEventType = eTCPAcceptEvent;
- xAskEvent.pvData = pxSocket;
- ( void ) xSendEventStructToIPTask( &xAskEvent, portMAX_DELAY );
- }
- if( pxClientSocket != NULL )
- {
- break;
- }
- if( xTimed == pdFALSE )
- {
- /* Only in the first round, check for non-blocking */
- xRemainingTime = pxSocket->xReceiveBlockTime;
- if( xRemainingTime == ( TickType_t ) 0 )
- {
- break;
- }
- /* Don't get here a second time */
- xTimed = pdTRUE;
- /* Fetch the current time */
- vTaskSetTimeOutState( &xTimeOut );
- }
- /* Has the timeout been reached? */
- if( xTaskCheckForTimeOut( &xTimeOut, &xRemainingTime ) != pdFALSE )
- {
- break;
- }
- /* Go sleeping until we get any down-stream event */
- ( void ) xEventGroupWaitBits( pxSocket->xEventGroup, ( EventBits_t ) eSOCKET_ACCEPT, pdTRUE /*xClearOnExit*/, pdFALSE /*xWaitAllBits*/, xRemainingTime );
- }
- }
- return pxClientSocket;
- }
- #endif /* ipconfigUSE_TCP */
- /*-----------------------------------------------------------*/
- #if ( ipconfigUSE_TCP == 1 )
- /**
- * @brief Read incoming data from a TCP socket. Only after the last
- * byte has been read, a close error might be returned.
- *
- * @param[in] xSocket: The socket owning the connection.
- * @param[out] pvBuffer: The buffer to store the incoming data in.
- * @param[in] uxBufferLength: The length of the buffer so that the function
- * does not do out of bound access.
- * @param[in] xFlags: The flags for conveying preference. The values
- * FREERTOS_MSG_DONTWAIT, FREERTOS_ZERO_COPY and/or
- * FREERTOS_MSG_PEEK can be used.
- *
- * @return The number of bytes actually received and stored in the pvBuffer.
- */
- BaseType_t FreeRTOS_recv( Socket_t xSocket,
- void * pvBuffer,
- size_t uxBufferLength,
- BaseType_t xFlags )
- {
- BaseType_t xByteCount;
- FreeRTOS_Socket_t * pxSocket = ( FreeRTOS_Socket_t * ) xSocket;
- TickType_t xRemainingTime;
- BaseType_t xTimed = pdFALSE;
- TimeOut_t xTimeOut;
- EventBits_t xEventBits = ( EventBits_t ) 0;
- /* Check if the socket is valid, has type TCP and if it is bound to a
- * port. */
- if( prvValidSocket( pxSocket, FREERTOS_IPPROTO_TCP, pdTRUE ) == pdFALSE )
- {
- xByteCount = -pdFREERTOS_ERRNO_EINVAL;
- }
- else if( ( ( ( uint32_t ) xFlags & ( uint32_t ) FREERTOS_ZERO_COPY ) != 0U ) &&
- ( pvBuffer == NULL ) )
- {
- /* In zero-copy mode, pvBuffer is a pointer to a pointer ( not NULL ). */
- xByteCount = -pdFREERTOS_ERRNO_EINVAL;
- }
- else
- {
- if( pxSocket->u.xTCP.rxStream != NULL )
- {
- xByteCount = ( BaseType_t ) uxStreamBufferGetSize( pxSocket->u.xTCP.rxStream );
- }
- else
- {
- xByteCount = 0;
- }
- while( xByteCount == 0 )
- {
- switch( ipNUMERIC_CAST( eIPTCPState_t, pxSocket->u.xTCP.ucTCPState ) )
- {
- case eCLOSED:
- case eCLOSE_WAIT: /* (server + client) waiting for a connection termination request from the local user. */
- case eCLOSING: /* (server + client) waiting for a connection termination request acknowledgement from the remote TCP. */
- if( pxSocket->u.xTCP.bits.bMallocError != pdFALSE_UNSIGNED )
- {
- /* The no-memory error has priority above the non-connected error.
- * Both are fatal and will lead to closing the socket. */
- xByteCount = -pdFREERTOS_ERRNO_ENOMEM;
- }
- else
- {
- xByteCount = -pdFREERTOS_ERRNO_ENOTCONN;
- }
- break;
- case eTCP_LISTEN:
- case eCONNECT_SYN:
- case eSYN_FIRST:
- case eSYN_RECEIVED:
- case eESTABLISHED:
- case eFIN_WAIT_1:
- case eFIN_WAIT_2:
- case eLAST_ACK:
- case eTIME_WAIT:
- default:
- /* Nothing. */
- break;
- }
- if( xByteCount < 0 )
- {
- break;
- }
- if( xTimed == pdFALSE )
- {
- /* Only in the first round, check for non-blocking. */
- xRemainingTime = pxSocket->xReceiveBlockTime;
- if( xRemainingTime == ( TickType_t ) 0 )
- {
- #if ( ipconfigSUPPORT_SIGNALS != 0 )
- {
- /* Just check for the interrupt flag. */
- xEventBits = xEventGroupWaitBits( pxSocket->xEventGroup, ( EventBits_t ) eSOCKET_INTR,
- pdTRUE /*xClearOnExit*/, pdFALSE /*xWaitAllBits*/, socketDONT_BLOCK );
- }
- #endif /* ipconfigSUPPORT_SIGNALS */
- break;
- }
- if( ( ( uint32_t ) xFlags & ( uint32_t ) FREERTOS_MSG_DONTWAIT ) != 0U )
- {
- break;
- }
- /* Don't get here a second time. */
- xTimed = pdTRUE;
- /* Fetch the current time. */
- vTaskSetTimeOutState( &xTimeOut );
- }
- /* Has the timeout been reached? */
- if( xTaskCheckForTimeOut( &xTimeOut, &xRemainingTime ) != pdFALSE )
- {
- break;
- }
- /* Block until there is a down-stream event. */
- xEventBits = xEventGroupWaitBits( pxSocket->xEventGroup,
- ( EventBits_t ) eSOCKET_RECEIVE | ( EventBits_t ) eSOCKET_CLOSED | ( EventBits_t ) eSOCKET_INTR,
- pdTRUE /*xClearOnExit*/, pdFALSE /*xWaitAllBits*/, xRemainingTime );
- #if ( ipconfigSUPPORT_SIGNALS != 0 )
- {
- if( ( xEventBits & ( EventBits_t ) eSOCKET_INTR ) != 0U )
- {
- break;
- }
- }
- #else
- {
- ( void ) xEventBits;
- }
- #endif /* ipconfigSUPPORT_SIGNALS */
- if( pxSocket->u.xTCP.rxStream != NULL )
- {
- xByteCount = ( BaseType_t ) uxStreamBufferGetSize( pxSocket->u.xTCP.rxStream );
- }
- else
- {
- xByteCount = 0;
- }
- }
- #if ( ipconfigSUPPORT_SIGNALS != 0 )
- if( ( xEventBits & ( EventBits_t ) eSOCKET_INTR ) != 0U )
- {
- if( ( xEventBits & ( ( EventBits_t ) eSOCKET_RECEIVE | ( EventBits_t ) eSOCKET_CLOSED ) ) != 0U )
- {
- /* Shouldn't have cleared other flags. */
- xEventBits &= ~( ( EventBits_t ) eSOCKET_INTR );
- ( void ) xEventGroupSetBits( pxSocket->xEventGroup, xEventBits );
- }
- xByteCount = -pdFREERTOS_ERRNO_EINTR;
- }
- else
- #endif /* ipconfigSUPPORT_SIGNALS */
- if( xByteCount > 0 )
- {
- if( ( ( uint32_t ) xFlags & ( uint32_t ) FREERTOS_ZERO_COPY ) == 0U )
- {
- BaseType_t xIsPeek = ( ( ( uint32_t ) xFlags & ( uint32_t ) FREERTOS_MSG_PEEK ) != 0U ) ? 1L : 0L;
- xByteCount = ( BaseType_t )
- uxStreamBufferGet( pxSocket->u.xTCP.rxStream,
- 0UL,
- ipPOINTER_CAST( uint8_t *, pvBuffer ),
- ( size_t ) uxBufferLength,
- xIsPeek );
- if( pxSocket->u.xTCP.bits.bLowWater != pdFALSE_UNSIGNED )
- {
- /* We had reached the low-water mark, now see if the flag
- * can be cleared */
- size_t uxFrontSpace = uxStreamBufferFrontSpace( pxSocket->u.xTCP.rxStream );
- if( uxFrontSpace >= pxSocket->u.xTCP.uxEnoughSpace )
- {
- pxSocket->u.xTCP.bits.bLowWater = pdFALSE;
- pxSocket->u.xTCP.bits.bWinChange = pdTRUE;
- pxSocket->u.xTCP.usTimeout = 1U; /* because bLowWater is cleared. */
- ( void ) xSendEventToIPTask( eTCPTimerEvent );
- }
- }
- }
- else
- {
- /* Zero-copy reception of data: pvBuffer is a pointer to a pointer. */
- xByteCount = ( BaseType_t ) uxStreamBufferGetPtr( pxSocket->u.xTCP.rxStream, ipPOINTER_CAST( uint8_t * *, pvBuffer ) );
- }
- }
- else
- {
- /* Nothing. */
- }
- } /* prvValidSocket() */
- return xByteCount;
- }
- #endif /* ipconfigUSE_TCP */
- /*-----------------------------------------------------------*/
- #if ( ipconfigUSE_TCP == 1 )
- /**
- * @brief Called from FreeRTOS_send(): some checks which will be done before
- * sending a TCP packed.
- *
- * @param[in] pxSocket: The socket owning the connection.
- * @param[in] uxDataLength: The length of the data to be sent.
- *
- * @return 0: representing OK, else a negative error code will be returned.
- */
- static int32_t prvTCPSendCheck( FreeRTOS_Socket_t * pxSocket,
- size_t uxDataLength )
- {
- int32_t xResult = 1;
- /* Is this a socket of type TCP and is it already bound to a port number ? */
- if( prvValidSocket( pxSocket, FREERTOS_IPPROTO_TCP, pdTRUE ) == pdFALSE )
- {
- xResult = -pdFREERTOS_ERRNO_EINVAL;
- }
- else if( pxSocket->u.xTCP.bits.bMallocError != pdFALSE_UNSIGNED )
- {
- xResult = -pdFREERTOS_ERRNO_ENOMEM;
- }
- else if( ( pxSocket->u.xTCP.ucTCPState == ( uint8_t ) eCLOSED ) ||
- ( pxSocket->u.xTCP.ucTCPState == ( uint8_t ) eCLOSE_WAIT ) ||
- ( pxSocket->u.xTCP.ucTCPState == ( uint8_t ) eCLOSING ) )
- {
- xResult = -pdFREERTOS_ERRNO_ENOTCONN;
- }
- else if( pxSocket->u.xTCP.bits.bFinSent != pdFALSE_UNSIGNED )
- {
- /* This TCP connection is closing already, the FIN flag has been sent.
- * Maybe it is still delivering or receiving data.
- * Return OK in order not to get closed/deleted too quickly */
- xResult = 0;
- }
- else if( uxDataLength == 0UL )
- {
- /* send() is being called to send zero bytes */
- xResult = 0;
- }
- else if( pxSocket->u.xTCP.txStream == NULL )
- {
- /* Create the outgoing stream only when it is needed */
- ( void ) prvTCPCreateStream( pxSocket, pdFALSE );
- if( pxSocket->u.xTCP.txStream == NULL )
- {
- xResult = -pdFREERTOS_ERRNO_ENOMEM;
- }
- }
- else
- {
- /* Nothing. */
- }
- return xResult;
- }
- #endif /* ipconfigUSE_TCP */
- /*-----------------------------------------------------------*/
- #if ( ipconfigUSE_TCP == 1 )
- /**
- * @brief Get a direct pointer to the circular transmit buffer.
- *
- * @param[in] xSocket: The socket owning the buffer.
- * @param[in] pxLength: This will contain the number of bytes that may be written.
- *
- * @return Head of the circular transmit buffer if all checks pass. Or else, NULL
- * is returned.
- */
- uint8_t * FreeRTOS_get_tx_head( ConstSocket_t xSocket,
- BaseType_t * pxLength )
- {
- uint8_t * pucReturn = NULL;
- const FreeRTOS_Socket_t * pxSocket = ( const FreeRTOS_Socket_t * ) xSocket;
- StreamBuffer_t * pxBuffer = NULL;
- *pxLength = 0;
- /* Confirm that this is a TCP socket before dereferencing structure
- * member pointers. */
- if( prvValidSocket( pxSocket, FREERTOS_IPPROTO_TCP, pdFALSE ) == pdTRUE )
- {
- pxBuffer = pxSocket->u.xTCP.txStream;
- if( pxBuffer != NULL )
- {
- BaseType_t xSpace = ( BaseType_t ) uxStreamBufferGetSpace( pxBuffer );
- BaseType_t xRemain = ( BaseType_t ) pxBuffer->LENGTH - ( BaseType_t ) pxBuffer->uxHead;
- *pxLength = FreeRTOS_min_BaseType( xSpace, xRemain );
- pucReturn = &( pxBuffer->ucArray[ pxBuffer->uxHead ] );
- }
- }
- return pucReturn;
- }
- #endif /* ipconfigUSE_TCP */
- /*-----------------------------------------------------------*/
- #if ( ipconfigUSE_TCP == 1 )
- /**
- * @brief Send data using a TCP socket. It is not necessary to have the socket
- * connected already. Outgoing data will be stored and delivered as soon as
- * the socket gets connected.
- *
- * @param[in] xSocket: The socket owning the connection.
- * @param[in] pvBuffer: The buffer containing the data.
- * @param[in] uxDataLength: The length of the data to be added.
- * @param[in] xFlags: This parameter is not used. (zero or FREERTOS_MSG_DONTWAIT).
- *
- * @return The number of bytes actually sent. Zero when nothing could be sent
- * or a negative error code in case an error occurred.
- */
- BaseType_t FreeRTOS_send( Socket_t xSocket,
- const void * pvBuffer,
- size_t uxDataLength,
- BaseType_t xFlags )
- {
- BaseType_t xByteCount = -pdFREERTOS_ERRNO_EINVAL;
- BaseType_t xBytesLeft;
- FreeRTOS_Socket_t * pxSocket = ( FreeRTOS_Socket_t * ) xSocket;
- TickType_t xRemainingTime;
- BaseType_t xTimed = pdFALSE;
- TimeOut_t xTimeOut;
- BaseType_t xCloseAfterSend;
- const uint8_t * pucSource = ipPOINTER_CAST( const uint8_t *, pvBuffer );
- /* Prevent compiler warnings about unused parameters. The parameter
- * may be used in future versions. */
- ( void ) xFlags;
- if( pvBuffer != NULL )
- {
- xByteCount = ( BaseType_t ) prvTCPSendCheck( pxSocket, uxDataLength );
- }
- if( xByteCount > 0 )
- {
- /* xBytesLeft is number of bytes to send, will count to zero. */
- xBytesLeft = ( BaseType_t ) uxDataLength;
- /* xByteCount is number of bytes that can be sent now. */
- xByteCount = ( BaseType_t ) uxStreamBufferGetSpace( pxSocket->u.xTCP.txStream );
- /* While there are still bytes to be sent. */
- while( xBytesLeft > 0 )
- {
- /* If txStream has space. */
- if( xByteCount > 0 )
- {
- /* Don't send more than necessary. */
- if( xByteCount > xBytesLeft )
- {
- xByteCount = xBytesLeft;
- }
- /* Is the close-after-send flag set and is this really the
- * last transmission? */
- if( ( pxSocket->u.xTCP.bits.bCloseAfterSend != pdFALSE_UNSIGNED ) && ( xByteCount == xBytesLeft ) )
- {
- xCloseAfterSend = pdTRUE;
- }
- else
- {
- xCloseAfterSend = pdFALSE;
- }
- /* The flag 'bCloseAfterSend' can be set before sending data
- * using setsockopt()
- *
- * When the last data packet is being sent out, a FIN flag will
- * be included to let the peer know that no more data is to be
- * expected. The use of 'bCloseAfterSend' is not mandatory, it
- * is just a faster way of transferring files (e.g. when using
- * FTP). */
- if( xCloseAfterSend != pdFALSE )
- {
- /* Now suspend the scheduler: sending the last data and
- * setting bCloseRequested must be done together */
- vTaskSuspendAll();
- pxSocket->u.xTCP.bits.bCloseRequested = pdTRUE;
- }
- xByteCount = ( BaseType_t ) uxStreamBufferAdd( pxSocket->u.xTCP.txStream, 0UL, pucSource, ( size_t ) xByteCount );
- if( xCloseAfterSend != pdFALSE )
- {
- /* Now when the IP-task transmits the data, it will also
- * see that bCloseRequested is true and include the FIN
- * flag to start closure of the connection. */
- ( void ) xTaskResumeAll();
- }
- /* Send a message to the IP-task so it can work on this
- * socket. Data is sent, let the IP-task work on it. */
- pxSocket->u.xTCP.usTimeout = 1U;
- if( xIsCallingFromIPTask() == pdFALSE )
- {
- /* Only send a TCP timer event when not called from the
- * IP-task. */
- ( void ) xSendEventToIPTask( eTCPTimerEvent );
- }
- xBytesLeft -= xByteCount;
- if( xBytesLeft == 0 )
- {
- break;
- }
- /* As there are still bytes left to be sent, increase the
- * data pointer. */
- pucSource = &( pucSource[ xByteCount ] );
- }
- /* Not all bytes have been sent. In case the socket is marked as
- * blocking sleep for a while. */
- if( xTimed == pdFALSE )
- {
- /* Only in the first round, check for non-blocking. */
- xRemainingTime = pxSocket->xSendBlockTime;
- #if ( ipconfigUSE_CALLBACKS != 0 )
- {
- if( xIsCallingFromIPTask() != pdFALSE )
- {
- /* If this send function is called from within a
- * call-back handler it may not block, otherwise
- * chances would be big to get a deadlock: the IP-task
- * waiting for itself. */
- xRemainingTime = ( TickType_t ) 0;
- }
- }
- #endif /* ipconfigUSE_CALLBACKS */
- if( xRemainingTime == ( TickType_t ) 0 )
- {
- break;
- }
- if( ( ( uint32_t ) xFlags & ( uint32_t ) FREERTOS_MSG_DONTWAIT ) != 0U )
- {
- break;
- }
- /* Don't get here a second time. */
- xTimed = pdTRUE;
- /* Fetch the current time. */
- vTaskSetTimeOutState( &xTimeOut );
- }
- else
- {
- /* Has the timeout been reached? */
- if( xTaskCheckForTimeOut( &xTimeOut, &xRemainingTime ) != pdFALSE )
- {
- break;
- }
- }
- /* Go sleeping until down-stream events are received. */
- ( void ) xEventGroupWaitBits( pxSocket->xEventGroup, ( EventBits_t ) eSOCKET_SEND | ( EventBits_t ) eSOCKET_CLOSED,
- pdTRUE /*xClearOnExit*/, pdFALSE /*xWaitAllBits*/, xRemainingTime );
- xByteCount = ( BaseType_t ) uxStreamBufferGetSpace( pxSocket->u.xTCP.txStream );
- }
- /* How much was actually sent? */
- xByteCount = ( ( BaseType_t ) uxDataLength ) - xBytesLeft;
- if( xByteCount == 0 )
- {
- if( pxSocket->u.xTCP.ucTCPState > ( uint8_t ) eESTABLISHED )
- {
- xByteCount = ( BaseType_t ) -pdFREERTOS_ERRNO_ENOTCONN;
- }
- else
- {
- if( ipconfigTCP_MAY_LOG_PORT( pxSocket->usLocalPort ) )
- {
- FreeRTOS_debug_printf( ( "FreeRTOS_send: %u -> %lxip:%d: no space\n",
- pxSocket->usLocalPort,
- pxSocket->u.xTCP.ulRemoteIP,
- pxSocket->u.xTCP.usRemotePort ) );
- }
- xByteCount = ( BaseType_t ) -pdFREERTOS_ERRNO_ENOSPC;
- }
- }
- }
- return xByteCount;
- }
- #endif /* ipconfigUSE_TCP */
- /*-----------------------------------------------------------*/
- #if ( ipconfigUSE_TCP == 1 )
- /**
- * @brief Request to put a socket in listen mode.
- *
- * @param[in] xSocket: the socket to be put in listening mode.
- * @param[in] xBacklog: Maximum number of child sockets.
- *
- * @return 0 in case of success, or else a negative error code is
- * returned.
- */
- BaseType_t FreeRTOS_listen( Socket_t xSocket,
- BaseType_t xBacklog )
- {
- FreeRTOS_Socket_t * pxSocket;
- BaseType_t xResult = 0;
- pxSocket = ( FreeRTOS_Socket_t * ) xSocket;
- /* listen() is allowed for a valid TCP socket in Closed state and already
- * bound. */
- if( prvValidSocket( pxSocket, FREERTOS_IPPROTO_TCP, pdTRUE ) == pdFALSE )
- {
- xResult = -pdFREERTOS_ERRNO_EOPNOTSUPP;
- }
- else if( ( pxSocket->u.xTCP.ucTCPState != ( uint8_t ) eCLOSED ) && ( pxSocket->u.xTCP.ucTCPState != ( uint8_t ) eCLOSE_WAIT ) )
- {
- /* Socket is in a wrong state. */
- xResult = -pdFREERTOS_ERRNO_EOPNOTSUPP;
- }
- else
- {
- /* Backlog is interpreted here as "the maximum number of child
- * sockets. */
- pxSocket->u.xTCP.usBacklog = ( uint16_t ) FreeRTOS_min_int32( ( int32_t ) 0xffff, ( int32_t ) xBacklog );
- /* This cleaning is necessary only if a listening socket is being
- * reused as it might have had a previous connection. */
- if( pxSocket->u.xTCP.bits.bReuseSocket != pdFALSE_UNSIGNED )
- {
- if( pxSocket->u.xTCP.rxStream != NULL )
- {
- vStreamBufferClear( pxSocket->u.xTCP.rxStream );
- }
- if( pxSocket->u.xTCP.txStream != NULL )
- {
- vStreamBufferClear( pxSocket->u.xTCP.txStream );
- }
- ( void ) memset( pxSocket->u.xTCP.xPacket.u.ucLastPacket, 0, sizeof( pxSocket->u.xTCP.xPacket.u.ucLastPacket ) );
- ( void ) memset( &pxSocket->u.xTCP.xTCPWindow, 0, sizeof( pxSocket->u.xTCP.xTCPWindow ) );
- ( void ) memset( &pxSocket->u.xTCP.bits, 0, sizeof( pxSocket->u.xTCP.bits ) );
- /* Now set the bReuseSocket flag again, because the bits have
- * just been cleared. */
- pxSocket->u.xTCP.bits.bReuseSocket = pdTRUE;
- }
- vTCPStateChange( pxSocket, eTCP_LISTEN );
- }
- return xResult;
- }
- #endif /* ipconfigUSE_TCP */
- /*-----------------------------------------------------------*/
- #if ( ipconfigUSE_TCP == 1 )
- /**
- * @brief Shutdown - This function will shut down the connection in both
- * directions. However, it will first deliver all data queued for
- * transmission, and also it will first wait to receive any missing
- * packets from the peer.
- *
- * @param[in] xSocket: The socket owning the connection.
- * @param[in] xHow: Not used. Just present to stick to Berkeley standard.
- *
- * @return 0 on successful shutdown or else a negative error code.
- */
- BaseType_t FreeRTOS_shutdown( Socket_t xSocket,
- BaseType_t xHow )
- {
- FreeRTOS_Socket_t * pxSocket = ( FreeRTOS_Socket_t * ) xSocket;
- BaseType_t xResult;
- if( prvValidSocket( pxSocket, FREERTOS_IPPROTO_TCP, pdTRUE ) == pdFALSE )
- {
- /*_RB_ Is this comment correct? The socket is not of a type that
- * supports the listen() operation. */
- xResult = -pdFREERTOS_ERRNO_EOPNOTSUPP;
- }
- else if( pxSocket->u.xTCP.ucTCPState != ( uint8_t ) eESTABLISHED )
- {
- /*_RB_ Is this comment correct? The socket is not of a type that
- * supports the listen() operation. */
- xResult = -pdFREERTOS_ERRNO_EOPNOTSUPP;
- }
- else
- {
- pxSocket->u.xTCP.bits.bUserShutdown = pdTRUE_UNSIGNED;
- /* Let the IP-task perform the shutdown of the connection. */
- pxSocket->u.xTCP.usTimeout = 1U;
- ( void ) xSendEventToIPTask( eTCPTimerEvent );
- xResult = 0;
- }
- ( void ) xHow;
- return xResult;
- }
- #endif /* ipconfigUSE_TCP */
- /*-----------------------------------------------------------*/
- #if ( ipconfigUSE_TCP == 1 )
- /**
- * @brief A TCP timer has expired, now check all TCP sockets for:
- * - Active connect
- * - Send a delayed ACK
- * - Send new data
- * - Send a keep-alive packet
- * - Check for timeout (in non-connected states only)
- *
- * @param[in] xWillSleep: Whether the calling task is going to sleep.
- *
- * @return Minimum amount of time before the timer shall expire.
- */
- TickType_t xTCPTimerCheck( BaseType_t xWillSleep )
- {
- FreeRTOS_Socket_t * pxSocket;
- TickType_t xShortest = pdMS_TO_TICKS( ( TickType_t ) ipTCP_TIMER_PERIOD_MS );
- TickType_t xNow = xTaskGetTickCount();
- static TickType_t xLastTime = 0U;
- TickType_t xDelta = xNow - xLastTime;
- const ListItem_t * pxEnd = listGET_END_MARKER( &xBoundTCPSocketsList );
- const ListItem_t * pxIterator = ( const ListItem_t * ) listGET_HEAD_ENTRY( &xBoundTCPSocketsList );
- xLastTime = xNow;
- if( xDelta == 0U )
- {
- xDelta = 1U;
- }
- while( pxIterator != pxEnd )
- {
- pxSocket = ipCAST_PTR_TO_TYPE_PTR( FreeRTOS_Socket_t, listGET_LIST_ITEM_OWNER( pxIterator ) );
- pxIterator = ( ListItem_t * ) listGET_NEXT( pxIterator );
- /* Sockets with 'timeout == 0' do not need any regular attention. */
- if( pxSocket->u.xTCP.usTimeout == 0U )
- {
- continue;
- }
- if( xDelta < ( TickType_t ) pxSocket->u.xTCP.usTimeout )
- {
- pxSocket->u.xTCP.usTimeout = ( uint16_t ) ( ( ( TickType_t ) pxSocket->u.xTCP.usTimeout ) - xDelta );
- }
- else
- {
- BaseType_t xRc;
- pxSocket->u.xTCP.usTimeout = 0U;
- xRc = xTCPSocketCheck( pxSocket );
- /* Within this function, the socket might want to send a delayed
- * ack or send out data or whatever it needs to do. */
- if( xRc < 0 )
- {
- /* Continue because the socket was deleted. */
- continue;
- }
- }
- /* In xEventBits the driver may indicate that the socket has
- * important events for the user. These are only done just before the
- * IP-task goes to sleep. */
- if( pxSocket->xEventBits != 0U )
- {
- if( xWillSleep != pdFALSE )
- {
- /* The IP-task is about to go to sleep, so messages can be
- * sent to the socket owners. */
- vSocketWakeUpUser( pxSocket );
- }
- else
- {
- /* Or else make sure this will be called again to wake-up
- * the sockets' owner. */
- xShortest = ( TickType_t ) 0;
- }
- }
- if( ( pxSocket->u.xTCP.usTimeout != 0U ) && ( xShortest > ( TickType_t ) pxSocket->u.xTCP.usTimeout ) )
- {
- xShortest = ( TickType_t ) pxSocket->u.xTCP.usTimeout;
- }
- }
- return xShortest;
- }
- #endif /* ipconfigUSE_TCP */
- /*-----------------------------------------------------------*/
- #if ( ipconfigUSE_TCP == 1 )
- /**
- * @brief As multiple sockets may be bound to the same local port number
- * looking up a socket is a little more complex: Both a local port,
- * and a remote port and IP address are being used to find a match.
- * For a socket in listening mode, the remote port and IP address
- * are both 0.
- *
- * @param[in] ulLocalIP: Local IP address. Ignored for now.
- * @param[in] uxLocalPort: Local port number.
- * @param[in] ulRemoteIP: Remote (peer) IP address.
- * @param[in] uxRemotePort: Remote (peer) port.
- *
- * @return The socket which was found.
- */
- FreeRTOS_Socket_t * pxTCPSocketLookup( uint32_t ulLocalIP,
- UBaseType_t uxLocalPort,
- uint32_t ulRemoteIP,
- UBaseType_t uxRemotePort )
- {
- const ListItem_t * pxIterator;
- FreeRTOS_Socket_t * pxResult = NULL, * pxListenSocket = NULL;
- const ListItem_t * pxEnd = listGET_END_MARKER( &xBoundTCPSocketsList );
- /* Parameter not yet supported. */
- ( void ) ulLocalIP;
- for( pxIterator = listGET_NEXT( pxEnd );
- pxIterator != pxEnd;
- pxIterator = listGET_NEXT( pxIterator ) )
- {
- FreeRTOS_Socket_t * pxSocket = ipCAST_PTR_TO_TYPE_PTR( FreeRTOS_Socket_t, listGET_LIST_ITEM_OWNER( pxIterator ) );
- if( pxSocket->usLocalPort == ( uint16_t ) uxLocalPort )
- {
- if( pxSocket->u.xTCP.ucTCPState == ( uint8_t ) eTCP_LISTEN )
- {
- /* If this is a socket listening to uxLocalPort, remember it
- * in case there is no perfect match. */
- pxListenSocket = pxSocket;
- }
- else if( ( pxSocket->u.xTCP.usRemotePort == ( uint16_t ) uxRemotePort ) && ( pxSocket->u.xTCP.ulRemoteIP == ulRemoteIP ) )
- {
- /* For sockets not in listening mode, find a match with
- * xLocalPort, ulRemoteIP AND xRemotePort. */
- pxResult = pxSocket;
- break;
- }
- else
- {
- /* This 'pxSocket' doesn't match. */
- }
- }
- }
- if( pxResult == NULL )
- {
- /* An exact match was not found, maybe a listening socket was
- * found. */
- pxResult = pxListenSocket;
- }
- return pxResult;
- }
- #endif /* ipconfigUSE_TCP */
- /*-----------------------------------------------------------*/
- #if ( ipconfigUSE_TCP == 1 )
- /**
- * @brief For the web server: borrow the circular Rx buffer for inspection.
- * HTML driver wants to see if a sequence of 13/10/13/10 is available.
- *
- * @param[in] xSocket: The socket whose Rx stream is to be returned.
- *
- * @return The Rx stream of the socket if all checks pass, else NULL.
- */
- const struct xSTREAM_BUFFER * FreeRTOS_get_rx_buf( ConstSocket_t xSocket )
- {
- const FreeRTOS_Socket_t * pxSocket = ( const FreeRTOS_Socket_t * ) xSocket;
- const struct xSTREAM_BUFFER * pxReturn = NULL;
- /* Confirm that this is a TCP socket before dereferencing structure
- * member pointers. */
- if( prvValidSocket( pxSocket, FREERTOS_IPPROTO_TCP, pdFALSE ) == pdTRUE )
- {
- pxReturn = pxSocket->u.xTCP.rxStream;
- }
- return pxReturn;
- }
- #endif /* ipconfigUSE_TCP */
- /*-----------------------------------------------------------*/
- #if ( ipconfigUSE_TCP == 1 )
- /**
- * @brief Create the stream buffer for the given socket.
- *
- * @param[in] pxSocket: the socket to create the stream for.
- * @param[in] xIsInputStream: Is this input stream? pdTRUE/pdFALSE?
- *
- * @return The stream buffer.
- */
- static StreamBuffer_t * prvTCPCreateStream( FreeRTOS_Socket_t * pxSocket,
- BaseType_t xIsInputStream )
- {
- StreamBuffer_t * pxBuffer;
- size_t uxLength;
- size_t uxSize;
- /* Now that a stream is created, the maximum size is fixed before
- * creation, it could still be changed with setsockopt(). */
- if( xIsInputStream != pdFALSE )
- {
- uxLength = pxSocket->u.xTCP.uxRxStreamSize;
- if( pxSocket->u.xTCP.uxLittleSpace == 0UL )
- {
- pxSocket->u.xTCP.uxLittleSpace = ( sock20_PERCENT * pxSocket->u.xTCP.uxRxStreamSize ) / sock100_PERCENT;
- }
- if( pxSocket->u.xTCP.uxEnoughSpace == 0UL )
- {
- pxSocket->u.xTCP.uxEnoughSpace = ( sock80_PERCENT * pxSocket->u.xTCP.uxRxStreamSize ) / sock100_PERCENT;
- }
- }
- else
- {
- uxLength = pxSocket->u.xTCP.uxTxStreamSize;
- }
- /* Add an extra 4 (or 8) bytes. */
- uxLength += sizeof( size_t );
- /* And make the length a multiple of sizeof( size_t ). */
- uxLength &= ~( sizeof( size_t ) - 1U );
- uxSize = ( sizeof( *pxBuffer ) + uxLength ) - sizeof( pxBuffer->ucArray );
- pxBuffer = ipCAST_PTR_TO_TYPE_PTR( StreamBuffer_t, pvPortMallocLarge( uxSize ) );
- if( pxBuffer == NULL )
- {
- FreeRTOS_debug_printf( ( "prvTCPCreateStream: malloc failed\n" ) );
- pxSocket->u.xTCP.bits.bMallocError = pdTRUE;
- vTCPStateChange( pxSocket, eCLOSE_WAIT );
- }
- else
- {
- /* Clear the markers of the stream */
- ( void ) memset( pxBuffer, 0, sizeof( *pxBuffer ) - sizeof( pxBuffer->ucArray ) );
- pxBuffer->LENGTH = ( size_t ) uxLength;
- if( xTCPWindowLoggingLevel != 0 )
- {
- FreeRTOS_debug_printf( ( "prvTCPCreateStream: %cxStream created %u bytes (total %u)\n", ( xIsInputStream != 0 ) ? 'R' : 'T', uxLength, uxSize ) );
- }
- if( xIsInputStream != 0 )
- {
- iptraceMEM_STATS_CREATE( tcpRX_STREAM_BUFFER, pxBuffer, uxSize );
- pxSocket->u.xTCP.rxStream = pxBuffer;
- }
- else
- {
- iptraceMEM_STATS_CREATE( tcpTX_STREAM_BUFFER, pxBuffer, uxSize );
- pxSocket->u.xTCP.txStream = pxBuffer;
- }
- }
- return pxBuffer;
- }
- #endif /* ipconfigUSE_TCP */
- /*-----------------------------------------------------------*/
- #if ( ipconfigUSE_TCP == 1 )
- /**
- * @brief Add data to the RxStream. When uxOffset > 0, data has come in out-of-order
- * and will be put in front of the head so it can not be popped by the user.
- *
- * @param[in] pxSocket: The socket to whose RxStream data is to be added.
- * @param[in] uxOffset: Offset of the packet.
- * @param[in] pcData: The data to be added to the RxStream.
- * @param[in] ulByteCount: Number of bytes in the data.
- *
- * @return The number of bytes actually added to the RxStream. Or else, a negative
- * error code is returned.
- */
- int32_t lTCPAddRxdata( FreeRTOS_Socket_t * pxSocket,
- size_t uxOffset,
- const uint8_t * pcData,
- uint32_t ulByteCount )
- {
- StreamBuffer_t * pxStream = pxSocket->u.xTCP.rxStream;
- int32_t xResult = 0;
- #if ( ipconfigUSE_CALLBACKS == 1 )
- BaseType_t bHasHandler = ipconfigIS_VALID_PROG_ADDRESS( pxSocket->u.xTCP.pxHandleReceive ) ? pdTRUE : pdFALSE;
- const uint8_t * pucBuffer = NULL;
- #endif /* ipconfigUSE_CALLBACKS */
- /* int32_t uxStreamBufferAdd( pxBuffer, uxOffset, pucData, aCount )
- * if( pucData != NULL ) copy data the the buffer
- * if( pucData == NULL ) no copying, just advance rxHead
- * if( uxOffset != 0 ) Just store data which has come out-of-order
- * if( uxOffset == 0 ) Also advance rxHead */
- if( pxStream == NULL )
- {
- pxStream = prvTCPCreateStream( pxSocket, pdTRUE );
- if( pxStream == NULL )
- {
- xResult = -1;
- }
- }
- if( xResult >= 0 )
- {
- #if ( ipconfigUSE_CALLBACKS == 1 )
- {
- if( ( bHasHandler != pdFALSE ) && ( uxStreamBufferGetSize( pxStream ) == 0U ) && ( uxOffset == 0UL ) && ( pcData != NULL ) )
- {
- /* Data can be passed directly to the user */
- pucBuffer = pcData;
- pcData = NULL;
- }
- }
- #endif /* ipconfigUSE_CALLBACKS */
- xResult = ( int32_t ) uxStreamBufferAdd( pxStream, uxOffset, pcData, ( size_t ) ulByteCount );
- #if ( ipconfigHAS_DEBUG_PRINTF != 0 )
- {
- if( xResult != ( int32_t ) ulByteCount )
- {
- FreeRTOS_debug_printf( ( "lTCPAddRxdata: at %u: %d/%u bytes (tail %u head %u space %u front %u)\n",
- ( UBaseType_t ) uxOffset,
- ( BaseType_t ) xResult,
- ( UBaseType_t ) ulByteCount,
- ( UBaseType_t ) pxStream->uxTail,
- ( UBaseType_t ) pxStream->uxHead,
- ( UBaseType_t ) uxStreamBufferFrontSpace( pxStream ),
- ( UBaseType_t ) pxStream->uxFront ) );
- }
- }
- #endif /* ipconfigHAS_DEBUG_PRINTF */
- if( uxOffset == 0U )
- {
- /* Data is being added to rxStream at the head (offs = 0) */
- #if ( ipconfigUSE_CALLBACKS == 1 )
- if( bHasHandler != pdFALSE )
- {
- /* The socket owner has installed an OnReceive handler. Pass the
- * Rx data, without copying from the rxStream, to the user. */
- for( ; ; )
- {
- uint8_t * ucReadPtr = NULL;
- uint32_t ulCount;
- if( pucBuffer != NULL )
- {
- ucReadPtr = ipPOINTER_CAST( uint8_t *, pucBuffer );
- ulCount = ulByteCount;
- pucBuffer = NULL;
- }
- else
- {
- ulCount = ( uint32_t ) uxStreamBufferGetPtr( pxStream, &( ucReadPtr ) );
- }
- if( ulCount == 0UL )
- {
- break;
- }
- ( void ) pxSocket->u.xTCP.pxHandleReceive( pxSocket, ucReadPtr, ( size_t ) ulCount );
- ( void ) uxStreamBufferGet( pxStream, 0UL, NULL, ( size_t ) ulCount, pdFALSE );
- }
- }
- else
- #endif /* ipconfigUSE_CALLBACKS */
- {
- /* See if running out of space. */
- if( pxSocket->u.xTCP.bits.bLowWater == pdFALSE_UNSIGNED )
- {
- size_t uxFrontSpace = uxStreamBufferFrontSpace( pxSocket->u.xTCP.rxStream );
- if( uxFrontSpace <= pxSocket->u.xTCP.uxLittleSpace )
- {
- pxSocket->u.xTCP.bits.bLowWater = pdTRUE;
- pxSocket->u.xTCP.bits.bWinChange = pdTRUE;
- /* bLowWater was reached, send the changed window size. */
- pxSocket->u.xTCP.usTimeout = 1U;
- ( void ) xSendEventToIPTask( eTCPTimerEvent );
- }
- }
- /* New incoming data is available, wake up the user. User's
- * semaphores will be set just before the IP-task goes asleep. */
- pxSocket->xEventBits |= ( EventBits_t ) eSOCKET_RECEIVE;
- #if ipconfigSUPPORT_SELECT_FUNCTION == 1
- {
- if( ( pxSocket->xSelectBits & ( EventBits_t ) eSELECT_READ ) != 0U )
- {
- pxSocket->xEventBits |= ( ( ( EventBits_t ) eSELECT_READ ) << SOCKET_EVENT_BIT_COUNT );
- }
- }
- #endif
- }
- }
- }
- return xResult;
- }
- #endif /* ipconfigUSE_TCP */
- /*-----------------------------------------------------------*/
- #if ( ipconfigUSE_TCP == 1 )
- /**
- * @brief Function to get the remote IP-address and port number.
- *
- * @param[in] xSocket: Socket owning the connection.
- * @param[out] pxAddress: The address pointer to which the address
- * is to be added.
- *
- * @return The size of the address being returned. Or else a negative
- * error code will be returned.
- */
- BaseType_t FreeRTOS_GetRemoteAddress( ConstSocket_t xSocket,
- struct freertos_sockaddr * pxAddress )
- {
- const FreeRTOS_Socket_t * pxSocket = ( const FreeRTOS_Socket_t * ) xSocket;
- BaseType_t xResult;
- if( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_TCP )
- {
- xResult = -pdFREERTOS_ERRNO_EINVAL;
- }
- else
- {
- /* BSD style sockets communicate IP and port addresses in network
- * byte order.
- * IP address of remote machine. */
- pxAddress->sin_addr = FreeRTOS_htonl( pxSocket->u.xTCP.ulRemoteIP );
- /* Port on remote machine. */
- pxAddress->sin_port = FreeRTOS_htons( pxSocket->u.xTCP.usRemotePort );
- xResult = ( BaseType_t ) sizeof( *pxAddress );
- }
- return xResult;
- }
- #endif /* ipconfigUSE_TCP */
- /*-----------------------------------------------------------*/
- #if ( ipconfigUSE_TCP == 1 )
- /**
- * @brief Check the number of bytes that may be added to txStream.
- *
- * @param[in] xSocket: The socket to be checked.
- *
- * @return the number of bytes that may be added to txStream or
- * else a negative error code.
- */
- BaseType_t FreeRTOS_maywrite( ConstSocket_t xSocket )
- {
- const FreeRTOS_Socket_t * pxSocket = ( const FreeRTOS_Socket_t * ) xSocket;
- BaseType_t xResult;
- if( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_TCP )
- {
- xResult = -pdFREERTOS_ERRNO_EINVAL;
- }
- else if( pxSocket->u.xTCP.ucTCPState != ( uint8_t ) eESTABLISHED )
- {
- if( ( pxSocket->u.xTCP.ucTCPState < ( uint8_t ) eCONNECT_SYN ) || ( pxSocket->u.xTCP.ucTCPState > ( EventBits_t ) eESTABLISHED ) )
- {
- xResult = -1;
- }
- else
- {
- xResult = 0;
- }
- }
- else if( pxSocket->u.xTCP.txStream == NULL )
- {
- xResult = ( BaseType_t ) pxSocket->u.xTCP.uxTxStreamSize;
- }
- else
- {
- xResult = ( BaseType_t ) uxStreamBufferGetSpace( pxSocket->u.xTCP.txStream );
- }
- return xResult;
- }
- #endif /* ipconfigUSE_TCP */
- /*-----------------------------------------------------------*/
- #if ( ipconfigUSE_TCP == 1 )
- /**
- * @brief Get the number of bytes that can be written in the Tx buffer
- * of the given socket.
- *
- * @param[in] xSocket: the socket to be checked.
- *
- * @return The bytes that can be written. Or else an error code.
- */
- BaseType_t FreeRTOS_tx_space( ConstSocket_t xSocket )
- {
- const FreeRTOS_Socket_t * pxSocket = ( const FreeRTOS_Socket_t * ) xSocket;
- BaseType_t xReturn;
- if( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_TCP )
- {
- xReturn = -pdFREERTOS_ERRNO_EINVAL;
- }
- else
- {
- if( pxSocket->u.xTCP.txStream != NULL )
- {
- xReturn = ( BaseType_t ) uxStreamBufferGetSpace( pxSocket->u.xTCP.txStream );
- }
- else
- {
- xReturn = ( BaseType_t ) pxSocket->u.xTCP.uxTxStreamSize;
- }
- }
- return xReturn;
- }
- #endif /* ipconfigUSE_TCP */
- /*-----------------------------------------------------------*/
- #if ( ipconfigUSE_TCP == 1 )
- /**
- * @brief Returns the number of bytes stored in the Tx buffer.
- *
- * @param[in] xSocket: The socket to be checked.
- *
- * @return The number of bytes stored in the Tx buffer of the socket.
- * Or an error code.
- */
- BaseType_t FreeRTOS_tx_size( ConstSocket_t xSocket )
- {
- const FreeRTOS_Socket_t * pxSocket = ( const FreeRTOS_Socket_t * ) xSocket;
- BaseType_t xReturn;
- if( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_TCP )
- {
- xReturn = -pdFREERTOS_ERRNO_EINVAL;
- }
- else
- {
- if( pxSocket->u.xTCP.txStream != NULL )
- {
- xReturn = ( BaseType_t ) uxStreamBufferGetSize( pxSocket->u.xTCP.txStream );
- }
- else
- {
- xReturn = 0;
- }
- }
- return xReturn;
- }
- #endif /* ipconfigUSE_TCP */
- /*-----------------------------------------------------------*/
- #if ( ipconfigUSE_TCP == 1 )
- /**
- * @brief Is the socket connected.
- *
- * @param[in] xSocket: The socket being checked.
- *
- * @return pdTRUE if TCP socket is connected.
- */
- BaseType_t FreeRTOS_issocketconnected( ConstSocket_t xSocket )
- {
- const FreeRTOS_Socket_t * pxSocket = ( const FreeRTOS_Socket_t * ) xSocket;
- BaseType_t xReturn = pdFALSE;
- if( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_TCP )
- {
- xReturn = -pdFREERTOS_ERRNO_EINVAL;
- }
- else
- {
- if( pxSocket->u.xTCP.ucTCPState >= ( uint8_t ) eESTABLISHED )
- {
- if( pxSocket->u.xTCP.ucTCPState < ( uint8_t ) eCLOSE_WAIT )
- {
- xReturn = pdTRUE;
- }
- }
- }
- return xReturn;
- }
- #endif /* ipconfigUSE_TCP */
- /*-----------------------------------------------------------*/
- #if ( ipconfigUSE_TCP == 1 )
- /**
- * @brief Get the actual value of Maximum Segment Size ( MSS ) being used.
- *
- * @param[in] xSocket: The socket whose MSS is to be returned.
- *
- * @return the actual size of MSS being used or an error code.
- */
- BaseType_t FreeRTOS_mss( ConstSocket_t xSocket )
- {
- const FreeRTOS_Socket_t * pxSocket = ( const FreeRTOS_Socket_t * ) xSocket;
- BaseType_t xReturn;
- if( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_TCP )
- {
- xReturn = -pdFREERTOS_ERRNO_EINVAL;
- }
- else
- {
- /* usCurMSS is declared as uint16_t to save space. FreeRTOS_mss()
- * will often be used in signed native-size expressions cast it to
- * BaseType_t. */
- xReturn = ( BaseType_t ) ( pxSocket->u.xTCP.usCurMSS );
- }
- return xReturn;
- }
- #endif /* ipconfigUSE_TCP */
- /*-----------------------------------------------------------*/
- #if ( ipconfigUSE_TCP == 1 )
- /**
- * @brief Get the connection status. The values correspond to the members
- * of the enum 'eIPTCPState_t'.
- *
- * @param[in] xSocket: Socket to get the connection status from.
- *
- * @return The connection status or an error code.
- *
- * @note For internal use only.
- */
- BaseType_t FreeRTOS_connstatus( ConstSocket_t xSocket )
- {
- const FreeRTOS_Socket_t * pxSocket = ( const FreeRTOS_Socket_t * ) xSocket;
- BaseType_t xReturn;
- if( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_TCP )
- {
- xReturn = -pdFREERTOS_ERRNO_EINVAL;
- }
- else
- {
- /* Cast it to BaseType_t. */
- xReturn = ( BaseType_t ) ( pxSocket->u.xTCP.ucTCPState );
- }
- return xReturn;
- }
- #endif /* ipconfigUSE_TCP */
- /*-----------------------------------------------------------*/
- #if ( ipconfigUSE_TCP == 1 )
- /**
- * @brief Returns the number of bytes which can be read from the RX stream buffer.
- *
- * @param[in] xSocket: the socket to get the number of bytes from.
- *
- * @return Returns the number of bytes which can be read. Or an error
- * code is returned.
- */
- BaseType_t FreeRTOS_rx_size( ConstSocket_t xSocket )
- {
- const FreeRTOS_Socket_t * pxSocket = ( const FreeRTOS_Socket_t * ) xSocket;
- BaseType_t xReturn;
- if( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_TCP )
- {
- xReturn = -pdFREERTOS_ERRNO_EINVAL;
- }
- else if( pxSocket->u.xTCP.rxStream != NULL )
- {
- xReturn = ( BaseType_t ) uxStreamBufferGetSize( pxSocket->u.xTCP.rxStream );
- }
- else
- {
- xReturn = 0;
- }
- return xReturn;
- }
- #endif /* ipconfigUSE_TCP */
- /*-----------------------------------------------------------*/
- #if 0
- /**
- * @brief Returns the number of packets that are stored in a UDP socket.
- *
- * @param[in] xSocket: the socket to get the number of bytes from.
- *
- * @return Returns the number of packets that are stored. Use FreeRTOS_recvfrom()
- * to retrieve those packets.
- */
- BaseType_t FreeRTOS_udp_rx_size( Socket_t xSocket )
- {
- BaseType_t xReturn = 0;
- const FreeRTOS_Socket_t * pxSocket = ( const FreeRTOS_Socket_t * ) xSocket;
- if( pxSocket->ucProtocol == ( uint8_t ) FREERTOS_IPPROTO_UDP )
- {
- xReturn = ( BaseType_t ) listCURRENT_LIST_LENGTH( &( pxSocket->u.xUDP.xWaitingPacketsList ) );
- }
- else
- {
- xReturn = -pdFREERTOS_ERRNO_EINVAL;
- }
- return xReturn;
- }
- #endif /* 0 */
- #if ( ipconfigUSE_TCP == 1 )
- /**
- * @brief Get the net status. The IP-task will print a summary of all sockets and
- * their connections.
- */
- void FreeRTOS_netstat( void )
- {
- IPStackEvent_t xAskEvent;
- /* Ask the IP-task to call vTCPNetStat()
- * to avoid accessing xBoundTCPSocketsList
- */
- xAskEvent.eEventType = eTCPNetStat;
- xAskEvent.pvData = ( void * ) NULL;
- ( void ) xSendEventStructToIPTask( &xAskEvent, pdMS_TO_TICKS( 1000U ) );
- }
- #endif /* ipconfigUSE_TCP */
- /*-----------------------------------------------------------*/
- #if ( ( ipconfigHAS_PRINTF != 0 ) && ( ipconfigUSE_TCP == 1 ) )
- /**
- * @brief Print a summary of all sockets and their connections.
- */
- void vTCPNetStat( void )
- {
- /* Show a simple listing of all created sockets and their connections */
- const ListItem_t * pxIterator;
- BaseType_t count = 0;
- size_t uxMinimum = uxGetMinimumFreeNetworkBuffers();
- size_t uxCurrent = uxGetNumberOfFreeNetworkBuffers();
- if( !listLIST_IS_INITIALISED( &xBoundTCPSocketsList ) )
- {
- FreeRTOS_printf( ( "PLUS-TCP not initialized\n" ) );
- }
- else
- {
- const ListItem_t * pxEndTCP = listGET_END_MARKER( &xBoundTCPSocketsList );
- const ListItem_t * pxEndUDP = listGET_END_MARKER( &xBoundUDPSocketsList );
- FreeRTOS_printf( ( "Prot Port IP-Remote : Port R/T Status Alive tmout Child\n" ) );
- for( pxIterator = listGET_HEAD_ENTRY( &xBoundTCPSocketsList );
- pxIterator != pxEndTCP;
- pxIterator = listGET_NEXT( pxIterator ) )
- {
- const FreeRTOS_Socket_t * pxSocket = ipCAST_CONST_PTR_TO_CONST_TYPE_PTR( FreeRTOS_Socket_t, listGET_LIST_ITEM_OWNER( pxIterator ) );
- #if ( ipconfigTCP_KEEP_ALIVE == 1 )
- TickType_t age = xTaskGetTickCount() - pxSocket->u.xTCP.xLastAliveTime;
- #else
- TickType_t age = 0U;
- #endif
- char ucChildText[ 16 ] = "";
- if( pxSocket->u.xTCP.ucTCPState == ( uint8_t ) eTCP_LISTEN )
- {
- /* Using function "snprintf". */
- const int32_t copied_len = snprintf( ucChildText, sizeof( ucChildText ), " %d/%d",
- ( int32_t ) pxSocket->u.xTCP.usChildCount,
- ( int32_t ) pxSocket->u.xTCP.usBacklog );
- ( void ) copied_len;
- /* These should never evaluate to false since the buffers are both shorter than 5-6 characters (<=65535) */
- configASSERT( copied_len >= 0 );
- configASSERT( copied_len < ( int32_t ) sizeof( ucChildText ) );
- }
- FreeRTOS_printf( ( "TCP %5d %-16lxip:%5d %d/%d %-13.13s %6lu %6u%s\n",
- pxSocket->usLocalPort, /* Local port on this machine */
- pxSocket->u.xTCP.ulRemoteIP, /* IP address of remote machine */
- pxSocket->u.xTCP.usRemotePort, /* Port on remote machine */
- ( pxSocket->u.xTCP.rxStream != NULL ) ? 1 : 0,
- ( pxSocket->u.xTCP.txStream != NULL ) ? 1 : 0,
- FreeRTOS_GetTCPStateName( pxSocket->u.xTCP.ucTCPState ),
- ( age > 999999u ) ? 999999u : age, /* Format 'age' for printing */
- pxSocket->u.xTCP.usTimeout,
- ucChildText ) );
- count++;
- }
- for( pxIterator = listGET_HEAD_ENTRY( &xBoundUDPSocketsList );
- pxIterator != pxEndUDP;
- pxIterator = listGET_NEXT( pxIterator ) )
- {
- /* Local port on this machine */
- FreeRTOS_printf( ( "UDP Port %5u\n",
- FreeRTOS_ntohs( listGET_LIST_ITEM_VALUE( pxIterator ) ) ) );
- count++;
- }
- FreeRTOS_printf( ( "FreeRTOS_netstat: %lu sockets %lu < %lu < %ld buffers free\n",
- ( UBaseType_t ) count,
- ( UBaseType_t ) uxMinimum,
- ( UBaseType_t ) uxCurrent,
- ( BaseType_t ) ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS ) );
- }
- }
- #endif /* ( ( ipconfigHAS_PRINTF != 0 ) && ( ipconfigUSE_TCP == 1 ) ) */
- /*-----------------------------------------------------------*/
- #if ( ipconfigSUPPORT_SELECT_FUNCTION == 1 )
- /**
- * @brief This internal non-blocking function will check all sockets that belong
- * to a select set. The events bits of each socket will be updated, and it
- * will check if an ongoing select() call must be interrupted because of an
- * event has occurred.
- *
- * @param[in] pxSocketSet: The socket-set which is to be waited on for change.
- */
- void vSocketSelect( SocketSelect_t * pxSocketSet )
- {
- BaseType_t xRound;
- EventBits_t xSocketBits, xBitsToClear;
- #if ipconfigUSE_TCP == 1
- BaseType_t xLastRound = 1;
- #else
- BaseType_t xLastRound = 0;
- #endif
- /* These flags will be switched on after checking the socket status. */
- EventBits_t xGroupBits = 0;
- for( xRound = 0; xRound <= xLastRound; xRound++ )
- {
- const ListItem_t * pxIterator;
- const ListItem_t * pxEnd;
- if( xRound == 0 )
- {
- pxEnd = listGET_END_MARKER( &xBoundUDPSocketsList );
- }
- #if ipconfigUSE_TCP == 1
- else
- {
- pxEnd = listGET_END_MARKER( &xBoundTCPSocketsList );
- }
- #endif /* ipconfigUSE_TCP == 1 */
- for( pxIterator = listGET_NEXT( pxEnd );
- pxIterator != pxEnd;
- pxIterator = listGET_NEXT( pxIterator ) )
- {
- FreeRTOS_Socket_t * pxSocket = ipCAST_PTR_TO_TYPE_PTR( FreeRTOS_Socket_t, listGET_LIST_ITEM_OWNER( pxIterator ) );
- if( pxSocket->pxSocketSet != pxSocketSet )
- {
- /* Socket does not belong to this select group. */
- continue;
- }
- xSocketBits = 0;
- #if ( ipconfigUSE_TCP == 1 )
- if( pxSocket->ucProtocol == ( uint8_t ) FREERTOS_IPPROTO_TCP )
- {
- /* Check if the socket has already been accepted by the
- * owner. If not, it is useless to return it from a
- * select(). */
- BaseType_t bAccepted = pdFALSE;
- if( pxSocket->u.xTCP.bits.bPassQueued == pdFALSE_UNSIGNED )
- {
- if( pxSocket->u.xTCP.bits.bPassAccept == pdFALSE_UNSIGNED )
- {
- bAccepted = pdTRUE;
- }
- }
- /* Is the set owner interested in READ events? */
- if( ( pxSocket->xSelectBits & ( EventBits_t ) eSELECT_READ ) != ( EventBits_t ) 0U )
- {
- if( pxSocket->u.xTCP.ucTCPState == ( uint8_t ) eTCP_LISTEN )
- {
- if( ( pxSocket->u.xTCP.pxPeerSocket != NULL ) && ( pxSocket->u.xTCP.pxPeerSocket->u.xTCP.bits.bPassAccept != pdFALSE_UNSIGNED ) )
- {
- xSocketBits |= ( EventBits_t ) eSELECT_READ;
- }
- }
- else if( ( pxSocket->u.xTCP.bits.bReuseSocket != pdFALSE_UNSIGNED ) && ( pxSocket->u.xTCP.bits.bPassAccept != pdFALSE_UNSIGNED ) )
- {
- /* This socket has the re-use flag. After connecting it turns into
- * a connected socket. Set the READ event, so that accept() will be called. */
- xSocketBits |= ( EventBits_t ) eSELECT_READ;
- }
- else if( ( bAccepted != 0 ) && ( FreeRTOS_recvcount( pxSocket ) > 0 ) )
- {
- xSocketBits |= ( EventBits_t ) eSELECT_READ;
- }
- else
- {
- /* Nothing. */
- }
- }
- /* Is the set owner interested in EXCEPTION events? */
- if( ( pxSocket->xSelectBits & ( EventBits_t ) eSELECT_EXCEPT ) != 0U )
- {
- if( ( pxSocket->u.xTCP.ucTCPState == ( uint8_t ) eCLOSE_WAIT ) || ( pxSocket->u.xTCP.ucTCPState == ( uint8_t ) eCLOSED ) )
- {
- xSocketBits |= ( EventBits_t ) eSELECT_EXCEPT;
- }
- }
- /* Is the set owner interested in WRITE events? */
- if( ( pxSocket->xSelectBits & ( EventBits_t ) eSELECT_WRITE ) != 0U )
- {
- BaseType_t bMatch = pdFALSE;
- if( bAccepted != 0 )
- {
- if( FreeRTOS_tx_space( pxSocket ) > 0 )
- {
- bMatch = pdTRUE;
- }
- }
- if( bMatch == pdFALSE )
- {
- if( ( pxSocket->u.xTCP.bits.bConnPrepared != pdFALSE_UNSIGNED ) &&
- ( pxSocket->u.xTCP.ucTCPState >= ( uint8_t ) eESTABLISHED ) &&
- ( pxSocket->u.xTCP.bits.bConnPassed == pdFALSE_UNSIGNED ) )
- {
- pxSocket->u.xTCP.bits.bConnPassed = pdTRUE;
- bMatch = pdTRUE;
- }
- }
- if( bMatch != pdFALSE )
- {
- xSocketBits |= ( EventBits_t ) eSELECT_WRITE;
- }
- }
- }
- else
- #endif /* ipconfigUSE_TCP == 1 */
- {
- /* Select events for UDP are simpler. */
- if( ( ( pxSocket->xSelectBits & ( EventBits_t ) eSELECT_READ ) != 0U ) &&
- ( listCURRENT_LIST_LENGTH( &( pxSocket->u.xUDP.xWaitingPacketsList ) ) > 0U ) )
- {
- xSocketBits |= ( EventBits_t ) eSELECT_READ;
- }
- /* The WRITE and EXCEPT bits are not used for UDP */
- } /* if( pxSocket->ucProtocol == FREERTOS_IPPROTO_TCP ) */
- /* Each socket keeps its own event flags, which are looked-up
- * by FreeRTOS_FD_ISSSET() */
- pxSocket->xSocketBits = xSocketBits;
- /* The ORed value will be used to set the bits in the event
- * group. */
- xGroupBits |= xSocketBits;
- } /* for( pxIterator ... ) */
- } /* for( xRound = 0; xRound <= xLastRound; xRound++ ) */
- xBitsToClear = xEventGroupGetBits( pxSocketSet->xSelectGroup );
- /* Now set the necessary bits. */
- xBitsToClear = ( xBitsToClear & ~xGroupBits ) & ( ( EventBits_t ) eSELECT_ALL );
- #if ( ipconfigSUPPORT_SIGNALS != 0 )
- {
- /* Maybe the socketset was signalled, but don't
- * clear the 'eSELECT_INTR' bit here, as it will be used
- * and cleared in FreeRTOS_select(). */
- xBitsToClear &= ~( ( EventBits_t ) eSELECT_INTR );
- }
- #endif /* ipconfigSUPPORT_SIGNALS */
- if( xBitsToClear != 0U )
- {
- ( void ) xEventGroupClearBits( pxSocketSet->xSelectGroup, xBitsToClear );
- }
- /* Now include eSELECT_CALL_IP to wakeup the caller. */
- ( void ) xEventGroupSetBits( pxSocketSet->xSelectGroup, xGroupBits | ( EventBits_t ) eSELECT_CALL_IP );
- }
- #endif /* ipconfigSUPPORT_SELECT_FUNCTION == 1 */
- /*-----------------------------------------------------------*/
- #if ( ipconfigSUPPORT_SIGNALS != 0 )
- /**
- * @brief Send a signal to the task which reads from this socket.
- * The socket will receive an event of the type 'eSOCKET_INTR'.
- * Any ongoing blocking API ( e.g. FreeRTOS_recv() ) will be terminated
- * and return the value -pdFREERTOS_ERRNO_EINTR ( -4 ).
- *
- * @param[in] xSocket: The socket that will be signalled.
- */
- BaseType_t FreeRTOS_SignalSocket( Socket_t xSocket )
- {
- FreeRTOS_Socket_t * pxSocket = ( FreeRTOS_Socket_t * ) xSocket;
- BaseType_t xReturn;
- if( pxSocket == NULL )
- {
- xReturn = -pdFREERTOS_ERRNO_EINVAL;
- }
- else
- #if ( ipconfigSUPPORT_SELECT_FUNCTION == 1 )
- if( ( pxSocket->pxSocketSet != NULL ) && ( pxSocket->pxSocketSet->xSelectGroup != NULL ) )
- {
- ( void ) xEventGroupSetBits( pxSocket->pxSocketSet->xSelectGroup, ( EventBits_t ) eSELECT_INTR );
- xReturn = 0;
- }
- else
- #endif /* ipconfigSUPPORT_SELECT_FUNCTION */
- if( pxSocket->xEventGroup != NULL )
- {
- ( void ) xEventGroupSetBits( pxSocket->xEventGroup, ( EventBits_t ) eSOCKET_INTR );
- xReturn = 0;
- }
- else
- {
- xReturn = -pdFREERTOS_ERRNO_EINVAL;
- }
- return xReturn;
- }
- #endif /* ipconfigSUPPORT_SIGNALS */
- /*-----------------------------------------------------------*/
- #if ( ipconfigSUPPORT_SIGNALS != 0 )
- /**
- * @brief The same as 'FreeRTOS_SignalSocket()', except that this function should
- * be called from an ISR context.
- *
- * @param[in] xSocket: The socket that will be signalled.
- * @param[in,out] pxHigherPriorityTaskWoken: will be set to non-zero in case a higher-
- * priority task has become runnable.
- */
- BaseType_t FreeRTOS_SignalSocketFromISR( Socket_t xSocket,
- BaseType_t * pxHigherPriorityTaskWoken )
- {
- FreeRTOS_Socket_t * pxSocket = ( FreeRTOS_Socket_t * ) xSocket;
- BaseType_t xReturn;
- IPStackEvent_t xEvent;
- configASSERT( pxSocket != NULL );
- configASSERT( pxSocket->ucProtocol == ( uint8_t ) FREERTOS_IPPROTO_TCP );
- configASSERT( pxSocket->xEventGroup != NULL );
- xEvent.eEventType = eSocketSignalEvent;
- xEvent.pvData = pxSocket;
- /* The IP-task will call FreeRTOS_SignalSocket for this socket. */
- xReturn = xQueueSendToBackFromISR( xNetworkEventQueue, &xEvent, pxHigherPriorityTaskWoken );
- return xReturn;
- }
- #endif /* ipconfigSUPPORT_SIGNALS */
- /*-----------------------------------------------------------*/
- #if 0
- #if ( ipconfigSUPPORT_SELECT_FUNCTION == 1 )
- struct pollfd
- {
- Socket_t fd; /* file descriptor */
- EventBits_t events; /* requested events */
- EventBits_t revents; /* returned events */
- };
- typedef BaseType_t nfds_t;
- BaseType_t poll( struct pollfd * fds,
- nfds_t nfds,
- BaseType_t timeout );
- BaseType_t poll( struct pollfd * fds,
- nfds_t nfds,
- BaseType_t timeout )
- {
- BaseType_t index;
- SocketSelect_t * pxSocketSet = NULL;
- BaseType_t xReturn = 0;
- /* See which socket-sets have been created and bound to the sockets involved. */
- for( index = 0; index < nfds; index++ )
- {
- FreeRTOS_Socket_t * pxSocket = ( FreeRTOS_Socket_t * ) fds[ index ].fd;
- if( pxSocket->pxSocketSet != NULL )
- {
- if( pxSocketSet == NULL )
- {
- /* Use this socket-set. */
- pxSocketSet = pxSocket->pxSocketSet;
- xReturn = 1;
- }
- else if( pxSocketSet == pxSocket->pxSocketSet )
- {
- /* Good: associated with the same socket-set. */
- }
- else
- {
- /* More than one socket-set is found: can not do a select on 2 sets. */
- xReturn = -1;
- break;
- }
- }
- }
- if( xReturn == 0 )
- {
- /* Create a new socket-set, and attach all sockets to it. */
- pxSocketSet = FreeRTOS_CreateSocketSet();
- if( pxSocketSet != NULL )
- {
- xReturn = 1;
- }
- else
- {
- xReturn = -2;
- }
- /* Memory leak: when the last socket closes, there is no more reference to
- * this socket-set. It should be marked as an automatic or anonymous socket-set,
- * so when closing the last member, its memory will be freed. */
- }
- if( xReturn > 0 )
- {
- /* Only one socket-set is found. Connect all sockets to this socket-set. */
- for( index = 0; index < nfds; index++ )
- {
- FreeRTOS_Socket_t * pxSocket = ( FreeRTOS_Socket_t * ) fds[ index ].fd;
- EventBits_t xEventBits = fds[ index ].events;
- FreeRTOS_FD_SET( pxSocket, pxSocketSet, xEventBits );
- FreeRTOS_FD_CLR( pxSocket, pxSocketSet, ( EventBits_t ) ~xEventBits );
- }
- /* And sleep until an event happens or a time-out. */
- xReturn = FreeRTOS_select( pxSocketSet, timeout );
- /* Now set the return events, copying from the socked field 'xSocketBits'. */
- for( index = 0; index < nfds; index++ )
- {
- FreeRTOS_Socket_t * pxSocket = ( FreeRTOS_Socket_t * ) fds[ index ].fd;
- fds[ index ].revents = pxSocket->xSocketBits & ( ( EventBits_t ) eSELECT_ALL );
- }
- }
- else
- {
- /* -1: Sockets are connected to different socket sets. */
- /* -2: FreeRTOS_CreateSocketSet() failed. */
- }
- return xReturn;
- }
- #endif /* ipconfigSUPPORT_SELECT_FUNCTION */
- #endif /* 0 */
|