mqtt5_options_storage.c 146 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984
  1. /**
  2. * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
  3. * SPDX-License-Identifier: Apache-2.0.
  4. */
  5. #include <aws/mqtt/private/v5/mqtt5_options_storage.h>
  6. #include <aws/common/clock.h>
  7. #include <aws/common/encoding.h>
  8. #include <aws/common/string.h>
  9. #include <aws/io/channel_bootstrap.h>
  10. #include <aws/io/event_loop.h>
  11. #include <aws/io/stream.h>
  12. #include <aws/mqtt/private/v5/mqtt5_client_impl.h>
  13. #include <aws/mqtt/private/v5/mqtt5_utils.h>
  14. #include <aws/mqtt/v5/mqtt5_client.h>
  15. #include <inttypes.h>
  16. /*********************************************************************************************************************
  17. * Property set
  18. ********************************************************************************************************************/
  19. int aws_mqtt5_user_property_set_init(
  20. struct aws_mqtt5_user_property_set *property_set,
  21. struct aws_allocator *allocator) {
  22. AWS_ZERO_STRUCT(*property_set);
  23. if (aws_array_list_init_dynamic(&property_set->properties, allocator, 0, sizeof(struct aws_mqtt5_user_property))) {
  24. return AWS_OP_ERR;
  25. }
  26. return AWS_OP_SUCCESS;
  27. }
  28. int aws_mqtt5_user_property_set_init_with_storage(
  29. struct aws_mqtt5_user_property_set *property_set,
  30. struct aws_allocator *allocator,
  31. struct aws_byte_buf *storage,
  32. size_t property_count,
  33. const struct aws_mqtt5_user_property *properties) {
  34. AWS_ZERO_STRUCT(*property_set);
  35. if (aws_array_list_init_dynamic(
  36. &property_set->properties, allocator, property_count, sizeof(struct aws_mqtt5_user_property))) {
  37. goto error;
  38. }
  39. for (size_t i = 0; i < property_count; ++i) {
  40. const struct aws_mqtt5_user_property *property = &properties[i];
  41. struct aws_mqtt5_user_property property_clone = *property;
  42. if (aws_byte_buf_append_and_update(storage, &property_clone.name)) {
  43. goto error;
  44. }
  45. if (aws_byte_buf_append_and_update(storage, &property_clone.value)) {
  46. goto error;
  47. }
  48. if (aws_array_list_push_back(&property_set->properties, &property_clone)) {
  49. goto error;
  50. }
  51. }
  52. return AWS_OP_SUCCESS;
  53. error:
  54. aws_mqtt5_user_property_set_clean_up(property_set);
  55. return AWS_OP_ERR;
  56. }
  57. void aws_mqtt5_user_property_set_clean_up(struct aws_mqtt5_user_property_set *property_set) {
  58. aws_array_list_clean_up(&property_set->properties);
  59. }
  60. size_t aws_mqtt5_user_property_set_size(const struct aws_mqtt5_user_property_set *property_set) {
  61. return aws_array_list_length(&property_set->properties);
  62. }
  63. int aws_mqtt5_user_property_set_get_property(
  64. const struct aws_mqtt5_user_property_set *property_set,
  65. size_t index,
  66. struct aws_mqtt5_user_property *property_out) {
  67. return aws_array_list_get_at(&property_set->properties, property_out, index);
  68. }
  69. int aws_mqtt5_user_property_set_add_stored_property(
  70. struct aws_mqtt5_user_property_set *property_set,
  71. struct aws_mqtt5_user_property *property) {
  72. return aws_array_list_push_back(&property_set->properties, property);
  73. }
  74. static void s_aws_mqtt5_user_property_set_log(
  75. struct aws_logger *log_handle,
  76. const struct aws_mqtt5_user_property *properties,
  77. size_t property_count,
  78. void *log_context,
  79. enum aws_log_level level,
  80. const char *log_prefix) {
  81. if (property_count == 0) {
  82. return;
  83. }
  84. AWS_LOGUF(
  85. log_handle,
  86. level,
  87. AWS_LS_MQTT5_GENERAL,
  88. "id=%p: %s with %zu user properties:",
  89. log_context,
  90. log_prefix,
  91. property_count);
  92. for (size_t i = 0; i < property_count; ++i) {
  93. const struct aws_mqtt5_user_property *property = &properties[i];
  94. AWS_LOGUF(
  95. log_handle,
  96. level,
  97. AWS_LS_MQTT5_GENERAL,
  98. "id=%p: %s user property %zu with name \"" PRInSTR "\", value \"" PRInSTR "\"",
  99. log_context,
  100. log_prefix,
  101. i,
  102. AWS_BYTE_CURSOR_PRI(property->name),
  103. AWS_BYTE_CURSOR_PRI(property->value));
  104. }
  105. }
  106. static size_t s_aws_mqtt5_user_property_set_compute_storage_size(
  107. const struct aws_mqtt5_user_property *properties,
  108. size_t property_count) {
  109. size_t storage_size = 0;
  110. for (size_t i = 0; i < property_count; ++i) {
  111. const struct aws_mqtt5_user_property *property = &properties[i];
  112. storage_size += property->name.len;
  113. storage_size += property->value.len;
  114. }
  115. return storage_size;
  116. }
  117. static int s_aws_mqtt5_user_property_set_validate(
  118. const struct aws_mqtt5_user_property *properties,
  119. size_t property_count,
  120. const char *log_prefix,
  121. void *log_context) {
  122. if (properties == NULL) {
  123. if (property_count == 0) {
  124. return AWS_OP_SUCCESS;
  125. } else {
  126. AWS_LOGF_ERROR(
  127. AWS_LS_MQTT5_GENERAL,
  128. "id=%p: %s - Invalid user property configuration, null properties, non-zero property count",
  129. log_context,
  130. log_prefix);
  131. return aws_raise_error(AWS_ERROR_MQTT5_USER_PROPERTY_VALIDATION);
  132. }
  133. }
  134. if (property_count > AWS_MQTT5_CLIENT_MAXIMUM_USER_PROPERTIES) {
  135. AWS_LOGF_ERROR(
  136. AWS_LS_MQTT5_GENERAL,
  137. "id=%p: %s - user property limit (%d) exceeded (%zu)",
  138. log_context,
  139. log_prefix,
  140. (int)AWS_MQTT5_CLIENT_MAXIMUM_USER_PROPERTIES,
  141. property_count);
  142. return aws_raise_error(AWS_ERROR_MQTT5_USER_PROPERTY_VALIDATION);
  143. }
  144. for (size_t i = 0; i < property_count; ++i) {
  145. const struct aws_mqtt5_user_property *property = &properties[i];
  146. if (property->name.len > UINT16_MAX) {
  147. AWS_LOGF_ERROR(
  148. AWS_LS_MQTT5_GENERAL,
  149. "id=%p: %s - user property #%zu name too long (%zu)",
  150. log_context,
  151. log_prefix,
  152. i,
  153. property->name.len);
  154. return aws_raise_error(AWS_ERROR_MQTT5_USER_PROPERTY_VALIDATION);
  155. }
  156. if (aws_mqtt5_validate_utf8_text(property->name)) {
  157. AWS_LOGF_ERROR(
  158. AWS_LS_MQTT5_GENERAL, "id=%p: %s - user property #%zu name not valid UTF8", log_context, log_prefix, i);
  159. return aws_raise_error(AWS_ERROR_MQTT5_USER_PROPERTY_VALIDATION);
  160. }
  161. if (property->value.len > UINT16_MAX) {
  162. AWS_LOGF_ERROR(
  163. AWS_LS_MQTT5_GENERAL,
  164. "id=%p: %s - user property #%zu value too long (%zu)",
  165. log_context,
  166. log_prefix,
  167. i,
  168. property->value.len);
  169. return aws_raise_error(AWS_ERROR_MQTT5_USER_PROPERTY_VALIDATION);
  170. }
  171. if (aws_mqtt5_validate_utf8_text(property->value)) {
  172. AWS_LOGF_ERROR(
  173. AWS_LS_MQTT5_GENERAL,
  174. "id=%p: %s - user property #%zu value not valid UTF8",
  175. log_context,
  176. log_prefix,
  177. i);
  178. return aws_raise_error(AWS_ERROR_MQTT5_USER_PROPERTY_VALIDATION);
  179. }
  180. }
  181. return AWS_OP_SUCCESS;
  182. }
  183. /*********************************************************************************************************************
  184. * Operation base
  185. ********************************************************************************************************************/
  186. struct aws_mqtt5_operation *aws_mqtt5_operation_acquire(struct aws_mqtt5_operation *operation) {
  187. if (operation == NULL) {
  188. return NULL;
  189. }
  190. aws_ref_count_acquire(&operation->ref_count);
  191. return operation;
  192. }
  193. struct aws_mqtt5_operation *aws_mqtt5_operation_release(struct aws_mqtt5_operation *operation) {
  194. if (operation != NULL) {
  195. aws_ref_count_release(&operation->ref_count);
  196. }
  197. return NULL;
  198. }
  199. void aws_mqtt5_operation_complete(
  200. struct aws_mqtt5_operation *operation,
  201. int error_code,
  202. enum aws_mqtt5_packet_type packet_type,
  203. const void *associated_view) {
  204. AWS_FATAL_ASSERT(operation->vtable != NULL);
  205. if (operation->vtable->aws_mqtt5_operation_completion_fn != NULL) {
  206. (*operation->vtable->aws_mqtt5_operation_completion_fn)(operation, error_code, packet_type, associated_view);
  207. }
  208. }
  209. void aws_mqtt5_operation_set_packet_id(struct aws_mqtt5_operation *operation, aws_mqtt5_packet_id_t packet_id) {
  210. AWS_FATAL_ASSERT(operation->vtable != NULL);
  211. if (operation->vtable->aws_mqtt5_operation_set_packet_id_fn != NULL) {
  212. (*operation->vtable->aws_mqtt5_operation_set_packet_id_fn)(operation, packet_id);
  213. }
  214. }
  215. aws_mqtt5_packet_id_t aws_mqtt5_operation_get_packet_id(const struct aws_mqtt5_operation *operation) {
  216. AWS_FATAL_ASSERT(operation->vtable != NULL);
  217. if (operation->vtable->aws_mqtt5_operation_get_packet_id_address_fn != NULL) {
  218. aws_mqtt5_packet_id_t *packet_id_ptr =
  219. (*operation->vtable->aws_mqtt5_operation_get_packet_id_address_fn)(operation);
  220. if (packet_id_ptr != NULL) {
  221. return *packet_id_ptr;
  222. }
  223. }
  224. return 0;
  225. }
  226. aws_mqtt5_packet_id_t *aws_mqtt5_operation_get_packet_id_address(const struct aws_mqtt5_operation *operation) {
  227. AWS_FATAL_ASSERT(operation->vtable != NULL);
  228. if (operation->vtable->aws_mqtt5_operation_get_packet_id_address_fn != NULL) {
  229. return (*operation->vtable->aws_mqtt5_operation_get_packet_id_address_fn)(operation);
  230. }
  231. return NULL;
  232. }
  233. int aws_mqtt5_operation_validate_vs_connection_settings(
  234. const struct aws_mqtt5_operation *operation,
  235. const struct aws_mqtt5_client *client) {
  236. AWS_FATAL_ASSERT(operation->vtable != NULL);
  237. AWS_FATAL_ASSERT(client->loop == NULL || aws_event_loop_thread_is_callers_thread(client->loop));
  238. /* If we have valid negotiated settings, check against them as well */
  239. if (aws_mqtt5_client_are_negotiated_settings_valid(client)) {
  240. const struct aws_mqtt5_negotiated_settings *settings = &client->negotiated_settings;
  241. size_t packet_size_in_bytes = 0;
  242. if (aws_mqtt5_packet_view_get_encoded_size(
  243. operation->packet_type, operation->packet_view, &packet_size_in_bytes)) {
  244. int error_code = aws_last_error();
  245. AWS_LOGF_ERROR(
  246. AWS_LS_MQTT5_CLIENT,
  247. "id=%p: error %d (%s) computing %s packet size",
  248. (void *)client,
  249. error_code,
  250. aws_error_debug_str(error_code),
  251. aws_mqtt5_packet_type_to_c_string(operation->packet_type));
  252. return aws_raise_error(AWS_ERROR_MQTT5_PACKET_VALIDATION);
  253. }
  254. if (packet_size_in_bytes > settings->maximum_packet_size_to_server) {
  255. AWS_LOGF_ERROR(
  256. AWS_LS_MQTT5_CLIENT,
  257. "id=%p: encoded %s packet size (%zu) exceeds server's maximum "
  258. "packet size (%" PRIu32 ")",
  259. (void *)client,
  260. aws_mqtt5_packet_type_to_c_string(operation->packet_type),
  261. packet_size_in_bytes,
  262. settings->maximum_packet_size_to_server);
  263. return aws_raise_error(AWS_ERROR_MQTT5_PACKET_VALIDATION);
  264. }
  265. }
  266. if (operation->vtable->aws_mqtt5_operation_validate_vs_connection_settings_fn != NULL) {
  267. return (*operation->vtable->aws_mqtt5_operation_validate_vs_connection_settings_fn)(
  268. operation->packet_view, client);
  269. }
  270. return AWS_OP_SUCCESS;
  271. }
  272. static struct aws_mqtt5_operation_vtable s_empty_operation_vtable = {
  273. .aws_mqtt5_operation_completion_fn = NULL,
  274. .aws_mqtt5_operation_set_packet_id_fn = NULL,
  275. .aws_mqtt5_operation_get_packet_id_address_fn = NULL,
  276. .aws_mqtt5_operation_validate_vs_connection_settings_fn = NULL,
  277. };
  278. /*********************************************************************************************************************
  279. * Connect
  280. ********************************************************************************************************************/
  281. int aws_mqtt5_packet_connect_view_validate(const struct aws_mqtt5_packet_connect_view *connect_options) {
  282. if (connect_options == NULL) {
  283. AWS_LOGF_ERROR(AWS_LS_MQTT5_GENERAL, "Null CONNECT options");
  284. return aws_raise_error(AWS_ERROR_INVALID_ARGUMENT);
  285. }
  286. if (connect_options->client_id.len > UINT16_MAX) {
  287. AWS_LOGF_ERROR(
  288. AWS_LS_MQTT5_GENERAL, "id=%p: aws_mqtt5_packet_connect_view - client id too long", (void *)connect_options);
  289. return aws_raise_error(AWS_ERROR_MQTT5_CONNECT_OPTIONS_VALIDATION);
  290. }
  291. if (aws_mqtt5_validate_utf8_text(connect_options->client_id)) {
  292. AWS_LOGF_ERROR(
  293. AWS_LS_MQTT5_GENERAL,
  294. "id=%p: aws_mqtt5_packet_connect_view - client id not valid UTF-8",
  295. (void *)connect_options);
  296. return aws_raise_error(AWS_ERROR_MQTT5_CONNECT_OPTIONS_VALIDATION);
  297. }
  298. if (connect_options->username != NULL) {
  299. if (connect_options->username->len > UINT16_MAX) {
  300. AWS_LOGF_ERROR(
  301. AWS_LS_MQTT5_GENERAL,
  302. "id=%p: aws_mqtt5_packet_connect_view - username too long",
  303. (void *)connect_options);
  304. return aws_raise_error(AWS_ERROR_MQTT5_CONNECT_OPTIONS_VALIDATION);
  305. }
  306. if (aws_mqtt5_validate_utf8_text(*connect_options->username)) {
  307. AWS_LOGF_ERROR(
  308. AWS_LS_MQTT5_GENERAL,
  309. "id=%p: aws_mqtt5_packet_connect_view - username not valid UTF-8",
  310. (void *)connect_options);
  311. return aws_raise_error(AWS_ERROR_MQTT5_CONNECT_OPTIONS_VALIDATION);
  312. }
  313. }
  314. if (connect_options->password != NULL) {
  315. if (connect_options->password->len > UINT16_MAX) {
  316. AWS_LOGF_ERROR(
  317. AWS_LS_MQTT5_GENERAL,
  318. "id=%p: aws_mqtt5_packet_connect_view - password too long",
  319. (void *)connect_options);
  320. return aws_raise_error(AWS_ERROR_MQTT5_CONNECT_OPTIONS_VALIDATION);
  321. }
  322. }
  323. if (connect_options->receive_maximum != NULL) {
  324. if (*connect_options->receive_maximum == 0) {
  325. AWS_LOGF_ERROR(
  326. AWS_LS_MQTT5_GENERAL,
  327. "id=%p: aws_mqtt5_packet_connect_view - receive maximum property of CONNECT packet may not be zero.",
  328. (void *)connect_options);
  329. return aws_raise_error(AWS_ERROR_MQTT5_CONNECT_OPTIONS_VALIDATION);
  330. }
  331. }
  332. if (connect_options->maximum_packet_size_bytes != NULL) {
  333. if (*connect_options->maximum_packet_size_bytes == 0) {
  334. AWS_LOGF_ERROR(
  335. AWS_LS_MQTT5_GENERAL,
  336. "id=%p: aws_mqtt5_packet_connect_view - maximum packet size property of CONNECT packet may not be "
  337. "zero.",
  338. (void *)connect_options);
  339. return aws_raise_error(AWS_ERROR_MQTT5_CONNECT_OPTIONS_VALIDATION);
  340. }
  341. }
  342. if (connect_options->will != NULL) {
  343. const struct aws_mqtt5_packet_publish_view *will_options = connect_options->will;
  344. if (aws_mqtt5_packet_publish_view_validate(will_options)) {
  345. AWS_LOGF_ERROR(
  346. AWS_LS_MQTT5_GENERAL,
  347. "id=%p: aws_mqtt5_packet_connect_view - CONNECT packet Will message failed validation",
  348. (void *)connect_options);
  349. return AWS_OP_ERR;
  350. }
  351. if (will_options->payload.len > UINT16_MAX) {
  352. AWS_LOGF_ERROR(
  353. AWS_LS_MQTT5_GENERAL,
  354. "id=%p: aws_mqtt5_packet_connect_view - will payload larger than %d",
  355. (void *)connect_options,
  356. (int)UINT16_MAX);
  357. return aws_raise_error(AWS_ERROR_MQTT5_CONNECT_OPTIONS_VALIDATION);
  358. }
  359. }
  360. if (connect_options->request_problem_information != NULL) {
  361. if (*connect_options->request_problem_information > 1) {
  362. AWS_LOGF_ERROR(
  363. AWS_LS_MQTT5_GENERAL,
  364. "id=%p: aws_mqtt5_packet_connect_view - CONNECT packet request problem information has invalid value",
  365. (void *)connect_options);
  366. return aws_raise_error(AWS_ERROR_MQTT5_CONNECT_OPTIONS_VALIDATION);
  367. }
  368. }
  369. if (connect_options->request_response_information != NULL) {
  370. if (*connect_options->request_response_information > 1) {
  371. AWS_LOGF_ERROR(
  372. AWS_LS_MQTT5_GENERAL,
  373. "id=%p: aws_mqtt5_packet_connect_view - CONNECT packet request response information has invalid value",
  374. (void *)connect_options);
  375. return aws_raise_error(AWS_ERROR_MQTT5_CONNECT_OPTIONS_VALIDATION);
  376. }
  377. }
  378. if (s_aws_mqtt5_user_property_set_validate(
  379. connect_options->user_properties,
  380. connect_options->user_property_count,
  381. "aws_mqtt5_packet_connect_view",
  382. (void *)connect_options)) {
  383. return AWS_OP_ERR;
  384. }
  385. if (connect_options->authentication_method != NULL || connect_options->authentication_data != NULL) {
  386. AWS_LOGF_ERROR(
  387. AWS_LS_MQTT5_GENERAL,
  388. "id=%p: aws_mqtt5_packet_connect_view - CONNECT packet has unsupported authentication fields set.",
  389. (void *)connect_options);
  390. return aws_raise_error(AWS_ERROR_MQTT5_CONNECT_OPTIONS_VALIDATION);
  391. // TODO: UTF-8 validation for authentication_method once supported.
  392. }
  393. return AWS_OP_SUCCESS;
  394. }
  395. void aws_mqtt5_packet_connect_view_log(
  396. const struct aws_mqtt5_packet_connect_view *connect_view,
  397. enum aws_log_level level) {
  398. struct aws_logger *log_handle = aws_logger_get_conditional(AWS_LS_MQTT5_GENERAL, level);
  399. if (log_handle == NULL) {
  400. return;
  401. }
  402. AWS_LOGUF(
  403. log_handle,
  404. level,
  405. AWS_LS_MQTT5_GENERAL,
  406. "id=%p: aws_mqtt5_packet_connect_view keep alive interval set to %" PRIu16,
  407. (void *)connect_view,
  408. connect_view->keep_alive_interval_seconds);
  409. AWS_LOGUF(
  410. log_handle,
  411. level,
  412. AWS_LS_MQTT5_GENERAL,
  413. "id=%p: aws_mqtt5_packet_connect_view client id set to \"" PRInSTR "\"",
  414. (void *)connect_view,
  415. AWS_BYTE_CURSOR_PRI(connect_view->client_id));
  416. if (connect_view->username != NULL) {
  417. /* Intentionally do not log username since it too can contain sensitive information */
  418. AWS_LOGUF(
  419. log_handle,
  420. level,
  421. AWS_LS_MQTT5_GENERAL,
  422. "id=%p: aws_mqtt5_packet_connect_view username set",
  423. (void *)connect_view);
  424. }
  425. if (connect_view->password != NULL) {
  426. AWS_LOGUF(
  427. log_handle,
  428. level,
  429. AWS_LS_MQTT5_GENERAL,
  430. "id=%p: aws_mqtt5_packet_connect_view password set",
  431. (void *)connect_view);
  432. }
  433. AWS_LOGUF(
  434. log_handle,
  435. level,
  436. AWS_LS_MQTT5_GENERAL,
  437. "id=%p: aws_mqtt5_packet_connect_view clean start set to %d",
  438. (void *)connect_view,
  439. (int)(connect_view->clean_start ? 1 : 0));
  440. if (connect_view->session_expiry_interval_seconds != NULL) {
  441. AWS_LOGUF(
  442. log_handle,
  443. level,
  444. AWS_LS_MQTT5_GENERAL,
  445. "id=%p: aws_mqtt5_packet_connect_view session expiry interval set to %" PRIu32,
  446. (void *)connect_view,
  447. *connect_view->session_expiry_interval_seconds);
  448. }
  449. if (connect_view->request_response_information != NULL) {
  450. AWS_LOGUF(
  451. log_handle,
  452. level,
  453. AWS_LS_MQTT5_GENERAL,
  454. "id=%p: aws_mqtt5_packet_connect_view request response information set to %d",
  455. (void *)connect_view,
  456. (int)*connect_view->request_response_information);
  457. }
  458. if (connect_view->request_problem_information) {
  459. AWS_LOGUF(
  460. log_handle,
  461. level,
  462. AWS_LS_MQTT5_GENERAL,
  463. "id=%p: aws_mqtt5_packet_connect_view request problem information set to %d",
  464. (void *)connect_view,
  465. (int)*connect_view->request_problem_information);
  466. }
  467. if (connect_view->receive_maximum != NULL) {
  468. AWS_LOGUF(
  469. log_handle,
  470. level,
  471. AWS_LS_MQTT5_GENERAL,
  472. "id=%p: aws_mqtt5_packet_connect_view receive maximum set to %" PRIu16,
  473. (void *)connect_view,
  474. *connect_view->receive_maximum);
  475. }
  476. if (connect_view->topic_alias_maximum != NULL) {
  477. AWS_LOGUF(
  478. log_handle,
  479. level,
  480. AWS_LS_MQTT5_GENERAL,
  481. "id=%p: aws_mqtt5_packet_connect_view topic alias maximum set to %" PRIu16,
  482. (void *)connect_view,
  483. *connect_view->topic_alias_maximum);
  484. }
  485. if (connect_view->maximum_packet_size_bytes != NULL) {
  486. AWS_LOGUF(
  487. log_handle,
  488. level,
  489. AWS_LS_MQTT5_GENERAL,
  490. "id=%p: aws_mqtt5_packet_connect_view maximum packet size set to %" PRIu32,
  491. (void *)connect_view,
  492. *connect_view->maximum_packet_size_bytes);
  493. }
  494. AWS_LOGUF(
  495. log_handle,
  496. level,
  497. AWS_LS_MQTT5_GENERAL,
  498. "id=%p: aws_mqtt5_packet_connect_view set will to (%p)",
  499. (void *)connect_view,
  500. (void *)connect_view->will);
  501. if (connect_view->will != NULL) {
  502. aws_mqtt5_packet_publish_view_log(connect_view->will, level);
  503. }
  504. if (connect_view->will_delay_interval_seconds != NULL) {
  505. AWS_LOGUF(
  506. log_handle,
  507. level,
  508. AWS_LS_MQTT5_GENERAL,
  509. "id=%p: aws_mqtt5_packet_connect_view will delay interval set to %" PRIu32,
  510. (void *)connect_view,
  511. *connect_view->will_delay_interval_seconds);
  512. }
  513. s_aws_mqtt5_user_property_set_log(
  514. log_handle,
  515. connect_view->user_properties,
  516. connect_view->user_property_count,
  517. (void *)connect_view,
  518. level,
  519. "aws_mqtt5_packet_connect_view");
  520. if (connect_view->authentication_method != NULL) {
  521. AWS_LOGUF(
  522. log_handle,
  523. level,
  524. AWS_LS_MQTT5_GENERAL,
  525. "id=%p: aws_mqtt5_packet_connect_view authentication method set",
  526. (void *)connect_view);
  527. }
  528. if (connect_view->password != NULL) {
  529. AWS_LOGUF(
  530. log_handle,
  531. level,
  532. AWS_LS_MQTT5_GENERAL,
  533. "id=%p: aws_mqtt5_packet_connect_view authentication data set",
  534. (void *)connect_view);
  535. }
  536. }
  537. void aws_mqtt5_packet_connect_storage_clean_up(struct aws_mqtt5_packet_connect_storage *storage) {
  538. if (storage == NULL) {
  539. return;
  540. }
  541. if (storage->will != NULL) {
  542. aws_mqtt5_packet_publish_storage_clean_up(storage->will);
  543. aws_mem_release(storage->allocator, storage->will);
  544. }
  545. aws_mqtt5_user_property_set_clean_up(&storage->user_properties);
  546. aws_byte_buf_clean_up_secure(&storage->storage);
  547. }
  548. static size_t s_aws_mqtt5_packet_connect_compute_storage_size(const struct aws_mqtt5_packet_connect_view *view) {
  549. if (view == NULL) {
  550. return 0;
  551. }
  552. size_t storage_size = 0;
  553. storage_size += view->client_id.len;
  554. if (view->username != NULL) {
  555. storage_size += view->username->len;
  556. }
  557. if (view->password != NULL) {
  558. storage_size += view->password->len;
  559. }
  560. storage_size +=
  561. s_aws_mqtt5_user_property_set_compute_storage_size(view->user_properties, view->user_property_count);
  562. if (view->authentication_method != NULL) {
  563. storage_size += view->authentication_method->len;
  564. }
  565. if (view->authentication_data != NULL) {
  566. storage_size += view->authentication_data->len;
  567. }
  568. return storage_size;
  569. }
  570. int aws_mqtt5_packet_connect_storage_init(
  571. struct aws_mqtt5_packet_connect_storage *storage,
  572. struct aws_allocator *allocator,
  573. const struct aws_mqtt5_packet_connect_view *view) {
  574. AWS_ZERO_STRUCT(*storage);
  575. struct aws_mqtt5_packet_connect_view *storage_view = &storage->storage_view;
  576. size_t storage_capacity = s_aws_mqtt5_packet_connect_compute_storage_size(view);
  577. if (aws_byte_buf_init(&storage->storage, allocator, storage_capacity)) {
  578. return AWS_OP_ERR;
  579. }
  580. storage->allocator = allocator;
  581. storage_view->keep_alive_interval_seconds = view->keep_alive_interval_seconds;
  582. storage_view->client_id = view->client_id;
  583. if (aws_byte_buf_append_and_update(&storage->storage, &storage_view->client_id)) {
  584. return AWS_OP_ERR;
  585. }
  586. if (view->username != NULL) {
  587. storage->username = *view->username;
  588. if (aws_byte_buf_append_and_update(&storage->storage, &storage->username)) {
  589. return AWS_OP_ERR;
  590. }
  591. storage_view->username = &storage->username;
  592. }
  593. if (view->password != NULL) {
  594. storage->password = *view->password;
  595. if (aws_byte_buf_append_and_update(&storage->storage, &storage->password)) {
  596. return AWS_OP_ERR;
  597. }
  598. storage_view->password = &storage->password;
  599. }
  600. storage_view->clean_start = view->clean_start;
  601. if (view->session_expiry_interval_seconds != NULL) {
  602. storage->session_expiry_interval_seconds = *view->session_expiry_interval_seconds;
  603. storage_view->session_expiry_interval_seconds = &storage->session_expiry_interval_seconds;
  604. }
  605. if (view->request_response_information != NULL) {
  606. storage->request_response_information = *view->request_response_information;
  607. storage_view->request_response_information = &storage->request_response_information;
  608. }
  609. if (view->request_problem_information != NULL) {
  610. storage->request_problem_information = *view->request_problem_information;
  611. storage_view->request_problem_information = &storage->request_problem_information;
  612. }
  613. if (view->receive_maximum != NULL) {
  614. storage->receive_maximum = *view->receive_maximum;
  615. storage_view->receive_maximum = &storage->receive_maximum;
  616. }
  617. if (view->topic_alias_maximum != NULL) {
  618. storage->topic_alias_maximum = *view->topic_alias_maximum;
  619. storage_view->topic_alias_maximum = &storage->topic_alias_maximum;
  620. }
  621. if (view->maximum_packet_size_bytes != NULL) {
  622. storage->maximum_packet_size_bytes = *view->maximum_packet_size_bytes;
  623. storage_view->maximum_packet_size_bytes = &storage->maximum_packet_size_bytes;
  624. }
  625. if (view->will != NULL) {
  626. storage->will = aws_mem_calloc(allocator, 1, sizeof(struct aws_mqtt5_packet_publish_storage));
  627. if (storage->will == NULL) {
  628. return AWS_OP_ERR;
  629. }
  630. if (aws_mqtt5_packet_publish_storage_init(storage->will, allocator, view->will)) {
  631. return AWS_OP_ERR;
  632. }
  633. storage_view->will = &storage->will->storage_view;
  634. }
  635. if (view->will_delay_interval_seconds != 0) {
  636. storage->will_delay_interval_seconds = *view->will_delay_interval_seconds;
  637. storage_view->will_delay_interval_seconds = &storage->will_delay_interval_seconds;
  638. }
  639. if (aws_mqtt5_user_property_set_init_with_storage(
  640. &storage->user_properties,
  641. allocator,
  642. &storage->storage,
  643. view->user_property_count,
  644. view->user_properties)) {
  645. return AWS_OP_ERR;
  646. }
  647. storage_view->user_property_count = aws_mqtt5_user_property_set_size(&storage->user_properties);
  648. storage_view->user_properties = storage->user_properties.properties.data;
  649. if (view->authentication_method != NULL) {
  650. storage->authentication_method = *view->authentication_method;
  651. if (aws_byte_buf_append_and_update(&storage->storage, &storage->authentication_method)) {
  652. return AWS_OP_ERR;
  653. }
  654. storage_view->authentication_method = &storage->authentication_method;
  655. }
  656. if (view->authentication_data != NULL) {
  657. storage->authentication_data = *view->authentication_data;
  658. if (aws_byte_buf_append_and_update(&storage->storage, &storage->authentication_data)) {
  659. return AWS_OP_ERR;
  660. }
  661. storage_view->authentication_data = &storage->authentication_data;
  662. }
  663. return AWS_OP_SUCCESS;
  664. }
  665. int aws_mqtt5_packet_connect_storage_init_from_external_storage(
  666. struct aws_mqtt5_packet_connect_storage *connect_storage,
  667. struct aws_allocator *allocator) {
  668. AWS_ZERO_STRUCT(*connect_storage);
  669. if (aws_mqtt5_user_property_set_init(&connect_storage->user_properties, allocator)) {
  670. return AWS_OP_ERR;
  671. }
  672. return AWS_OP_SUCCESS;
  673. }
  674. static void s_destroy_operation_connect(void *object) {
  675. if (object == NULL) {
  676. return;
  677. }
  678. struct aws_mqtt5_operation_connect *connect_op = object;
  679. aws_mqtt5_packet_connect_storage_clean_up(&connect_op->options_storage);
  680. aws_mem_release(connect_op->allocator, connect_op);
  681. }
  682. struct aws_mqtt5_operation_connect *aws_mqtt5_operation_connect_new(
  683. struct aws_allocator *allocator,
  684. const struct aws_mqtt5_packet_connect_view *connect_options) {
  685. AWS_PRECONDITION(allocator != NULL);
  686. AWS_PRECONDITION(connect_options != NULL);
  687. if (aws_mqtt5_packet_connect_view_validate(connect_options)) {
  688. return NULL;
  689. }
  690. struct aws_mqtt5_operation_connect *connect_op =
  691. aws_mem_calloc(allocator, 1, sizeof(struct aws_mqtt5_operation_connect));
  692. if (connect_op == NULL) {
  693. return NULL;
  694. }
  695. connect_op->allocator = allocator;
  696. connect_op->base.vtable = &s_empty_operation_vtable;
  697. connect_op->base.packet_type = AWS_MQTT5_PT_CONNECT;
  698. aws_ref_count_init(&connect_op->base.ref_count, connect_op, s_destroy_operation_connect);
  699. connect_op->base.impl = connect_op;
  700. if (aws_mqtt5_packet_connect_storage_init(&connect_op->options_storage, allocator, connect_options)) {
  701. goto error;
  702. }
  703. connect_op->base.packet_view = &connect_op->options_storage.storage_view;
  704. return connect_op;
  705. error:
  706. aws_mqtt5_operation_release(&connect_op->base);
  707. return NULL;
  708. }
  709. /*********************************************************************************************************************
  710. * Connack
  711. ********************************************************************************************************************/
  712. static size_t s_aws_mqtt5_packet_connack_compute_storage_size(const struct aws_mqtt5_packet_connack_view *view) {
  713. if (view == NULL) {
  714. return 0;
  715. }
  716. size_t storage_size = 0;
  717. if (view->assigned_client_identifier != NULL) {
  718. storage_size += view->assigned_client_identifier->len;
  719. }
  720. if (view->reason_string != NULL) {
  721. storage_size += view->reason_string->len;
  722. }
  723. if (view->response_information != NULL) {
  724. storage_size += view->response_information->len;
  725. }
  726. if (view->server_reference != NULL) {
  727. storage_size += view->server_reference->len;
  728. }
  729. if (view->authentication_method != NULL) {
  730. storage_size += view->authentication_method->len;
  731. }
  732. if (view->authentication_data != NULL) {
  733. storage_size += view->authentication_data->len;
  734. }
  735. storage_size +=
  736. s_aws_mqtt5_user_property_set_compute_storage_size(view->user_properties, view->user_property_count);
  737. return storage_size;
  738. }
  739. int aws_mqtt5_packet_connack_storage_init(
  740. struct aws_mqtt5_packet_connack_storage *connack_storage,
  741. struct aws_allocator *allocator,
  742. const struct aws_mqtt5_packet_connack_view *connack_view) {
  743. AWS_ZERO_STRUCT(*connack_storage);
  744. size_t storage_capacity = s_aws_mqtt5_packet_connack_compute_storage_size(connack_view);
  745. if (aws_byte_buf_init(&connack_storage->storage, allocator, storage_capacity)) {
  746. return AWS_OP_ERR;
  747. }
  748. struct aws_mqtt5_packet_connack_view *stored_view = &connack_storage->storage_view;
  749. connack_storage->allocator = allocator;
  750. stored_view->session_present = connack_view->session_present;
  751. stored_view->reason_code = connack_view->reason_code;
  752. if (connack_view->session_expiry_interval != NULL) {
  753. connack_storage->session_expiry_interval = *connack_view->session_expiry_interval;
  754. stored_view->session_expiry_interval = &connack_storage->session_expiry_interval;
  755. }
  756. if (connack_view->receive_maximum != NULL) {
  757. connack_storage->receive_maximum = *connack_view->receive_maximum;
  758. stored_view->receive_maximum = &connack_storage->receive_maximum;
  759. }
  760. if (connack_view->maximum_qos != NULL) {
  761. connack_storage->maximum_qos = *connack_view->maximum_qos;
  762. stored_view->maximum_qos = &connack_storage->maximum_qos;
  763. }
  764. if (connack_view->retain_available != NULL) {
  765. connack_storage->retain_available = *connack_view->retain_available;
  766. stored_view->retain_available = &connack_storage->retain_available;
  767. }
  768. if (connack_view->maximum_packet_size != NULL) {
  769. connack_storage->maximum_packet_size = *connack_view->maximum_packet_size;
  770. stored_view->maximum_packet_size = &connack_storage->maximum_packet_size;
  771. }
  772. if (connack_view->assigned_client_identifier != NULL) {
  773. connack_storage->assigned_client_identifier = *connack_view->assigned_client_identifier;
  774. if (aws_byte_buf_append_and_update(&connack_storage->storage, &connack_storage->assigned_client_identifier)) {
  775. return AWS_OP_ERR;
  776. }
  777. stored_view->assigned_client_identifier = &connack_storage->assigned_client_identifier;
  778. }
  779. if (connack_view->topic_alias_maximum != NULL) {
  780. connack_storage->topic_alias_maximum = *connack_view->topic_alias_maximum;
  781. stored_view->topic_alias_maximum = &connack_storage->topic_alias_maximum;
  782. }
  783. if (connack_view->reason_string != NULL) {
  784. connack_storage->reason_string = *connack_view->reason_string;
  785. if (aws_byte_buf_append_and_update(&connack_storage->storage, &connack_storage->reason_string)) {
  786. return AWS_OP_ERR;
  787. }
  788. stored_view->reason_string = &connack_storage->reason_string;
  789. }
  790. if (connack_view->wildcard_subscriptions_available != NULL) {
  791. connack_storage->wildcard_subscriptions_available = *connack_view->wildcard_subscriptions_available;
  792. stored_view->wildcard_subscriptions_available = &connack_storage->wildcard_subscriptions_available;
  793. }
  794. if (connack_view->subscription_identifiers_available != NULL) {
  795. connack_storage->subscription_identifiers_available = *connack_view->subscription_identifiers_available;
  796. stored_view->subscription_identifiers_available = &connack_storage->subscription_identifiers_available;
  797. }
  798. if (connack_view->shared_subscriptions_available != NULL) {
  799. connack_storage->shared_subscriptions_available = *connack_view->shared_subscriptions_available;
  800. stored_view->shared_subscriptions_available = &connack_storage->shared_subscriptions_available;
  801. }
  802. if (connack_view->server_keep_alive != NULL) {
  803. connack_storage->server_keep_alive = *connack_view->server_keep_alive;
  804. stored_view->server_keep_alive = &connack_storage->server_keep_alive;
  805. }
  806. if (connack_view->response_information != NULL) {
  807. connack_storage->response_information = *connack_view->response_information;
  808. if (aws_byte_buf_append_and_update(&connack_storage->storage, &connack_storage->response_information)) {
  809. return AWS_OP_ERR;
  810. }
  811. stored_view->response_information = &connack_storage->response_information;
  812. }
  813. if (connack_view->server_reference != NULL) {
  814. connack_storage->server_reference = *connack_view->server_reference;
  815. if (aws_byte_buf_append_and_update(&connack_storage->storage, &connack_storage->server_reference)) {
  816. return AWS_OP_ERR;
  817. }
  818. stored_view->server_reference = &connack_storage->server_reference;
  819. }
  820. if (connack_view->authentication_method != NULL) {
  821. connack_storage->authentication_method = *connack_view->authentication_method;
  822. if (aws_byte_buf_append_and_update(&connack_storage->storage, &connack_storage->authentication_method)) {
  823. return AWS_OP_ERR;
  824. }
  825. stored_view->authentication_method = &connack_storage->authentication_method;
  826. }
  827. if (connack_view->authentication_data != NULL) {
  828. connack_storage->authentication_data = *connack_view->authentication_data;
  829. if (aws_byte_buf_append_and_update(&connack_storage->storage, &connack_storage->authentication_data)) {
  830. return AWS_OP_ERR;
  831. }
  832. stored_view->authentication_data = &connack_storage->authentication_data;
  833. }
  834. if (aws_mqtt5_user_property_set_init_with_storage(
  835. &connack_storage->user_properties,
  836. allocator,
  837. &connack_storage->storage,
  838. connack_view->user_property_count,
  839. connack_view->user_properties)) {
  840. return AWS_OP_ERR;
  841. }
  842. stored_view->user_property_count = aws_mqtt5_user_property_set_size(&connack_storage->user_properties);
  843. stored_view->user_properties = connack_storage->user_properties.properties.data;
  844. return AWS_OP_SUCCESS;
  845. }
  846. int aws_mqtt5_packet_connack_storage_init_from_external_storage(
  847. struct aws_mqtt5_packet_connack_storage *connack_storage,
  848. struct aws_allocator *allocator) {
  849. AWS_ZERO_STRUCT(*connack_storage);
  850. if (aws_mqtt5_user_property_set_init(&connack_storage->user_properties, allocator)) {
  851. return AWS_OP_ERR;
  852. }
  853. return AWS_OP_SUCCESS;
  854. }
  855. void aws_mqtt5_packet_connack_storage_clean_up(struct aws_mqtt5_packet_connack_storage *connack_storage) {
  856. if (connack_storage == NULL) {
  857. return;
  858. }
  859. aws_mqtt5_user_property_set_clean_up(&connack_storage->user_properties);
  860. aws_byte_buf_clean_up(&connack_storage->storage);
  861. }
  862. void aws_mqtt5_packet_connack_view_log(
  863. const struct aws_mqtt5_packet_connack_view *connack_view,
  864. enum aws_log_level level) {
  865. struct aws_logger *log_handle = aws_logger_get_conditional(AWS_LS_MQTT5_GENERAL, level);
  866. if (log_handle == NULL) {
  867. return;
  868. }
  869. AWS_LOGUF(
  870. log_handle,
  871. level,
  872. AWS_LS_MQTT5_GENERAL,
  873. "id=%p: aws_mqtt5_packet_connack_view reason code set to %d (%s)",
  874. (void *)connack_view,
  875. (int)connack_view->reason_code,
  876. aws_mqtt5_connect_reason_code_to_c_string(connack_view->reason_code));
  877. AWS_LOGUF(
  878. log_handle,
  879. level,
  880. AWS_LS_MQTT5_GENERAL,
  881. "id=%p: aws_mqtt5_packet_connack_view session present set to %d",
  882. (void *)connack_view,
  883. (int)connack_view->session_present);
  884. if (connack_view->session_expiry_interval != NULL) {
  885. AWS_LOGUF(
  886. log_handle,
  887. level,
  888. AWS_LS_MQTT5_GENERAL,
  889. "id=%p: aws_mqtt5_packet_connack_view session expiry interval set to %" PRIu32,
  890. (void *)connack_view,
  891. *connack_view->session_expiry_interval);
  892. }
  893. if (connack_view->receive_maximum != NULL) {
  894. AWS_LOGUF(
  895. log_handle,
  896. level,
  897. AWS_LS_MQTT5_GENERAL,
  898. "id=%p: aws_mqtt5_packet_connack_view receive maximum set to %" PRIu16,
  899. (void *)connack_view,
  900. *connack_view->receive_maximum);
  901. }
  902. if (connack_view->maximum_qos != NULL) {
  903. AWS_LOGUF(
  904. log_handle,
  905. level,
  906. AWS_LS_MQTT5_GENERAL,
  907. "id=%p: aws_mqtt5_packet_connack_view maximum qos set to %d",
  908. (void *)connack_view,
  909. (int)(*connack_view->maximum_qos));
  910. }
  911. if (connack_view->retain_available != NULL) {
  912. AWS_LOGUF(
  913. log_handle,
  914. level,
  915. AWS_LS_MQTT5_GENERAL,
  916. "id=%p: aws_mqtt5_packet_connack_view retain available set to %d",
  917. (void *)connack_view,
  918. (int)(*connack_view->retain_available));
  919. }
  920. if (connack_view->maximum_packet_size != NULL) {
  921. AWS_LOGUF(
  922. log_handle,
  923. level,
  924. AWS_LS_MQTT5_GENERAL,
  925. "id=%p: aws_mqtt5_packet_connack_view maximum packet size set to %" PRIu32,
  926. (void *)connack_view,
  927. *connack_view->maximum_packet_size);
  928. }
  929. if (connack_view->assigned_client_identifier != NULL) {
  930. AWS_LOGUF(
  931. log_handle,
  932. level,
  933. AWS_LS_MQTT5_GENERAL,
  934. "id=%p: aws_mqtt5_packet_connack_view assigned client identifier set to \"" PRInSTR "\"",
  935. (void *)connack_view,
  936. AWS_BYTE_CURSOR_PRI(*connack_view->assigned_client_identifier));
  937. }
  938. if (connack_view->topic_alias_maximum != NULL) {
  939. AWS_LOGUF(
  940. log_handle,
  941. level,
  942. AWS_LS_MQTT5_GENERAL,
  943. "id=%p: aws_mqtt5_packet_connack_view topic alias maximum set to %" PRIu16,
  944. (void *)connack_view,
  945. *connack_view->topic_alias_maximum);
  946. }
  947. if (connack_view->reason_string != NULL) {
  948. AWS_LOGUF(
  949. log_handle,
  950. level,
  951. AWS_LS_MQTT5_GENERAL,
  952. "id=%p: aws_mqtt5_packet_connack_view reason string set to \"" PRInSTR "\"",
  953. (void *)connack_view,
  954. AWS_BYTE_CURSOR_PRI(*connack_view->reason_string));
  955. }
  956. if (connack_view->wildcard_subscriptions_available != NULL) {
  957. AWS_LOGUF(
  958. log_handle,
  959. level,
  960. AWS_LS_MQTT5_GENERAL,
  961. "id=%p: aws_mqtt5_packet_connack_view wildcard subscriptions available set to %d",
  962. (void *)connack_view,
  963. (int)(*connack_view->wildcard_subscriptions_available));
  964. }
  965. if (connack_view->subscription_identifiers_available != NULL) {
  966. AWS_LOGUF(
  967. log_handle,
  968. level,
  969. AWS_LS_MQTT5_GENERAL,
  970. "id=%p: aws_mqtt5_packet_connack_view subscription identifiers available set to %d",
  971. (void *)connack_view,
  972. (int)(*connack_view->subscription_identifiers_available));
  973. }
  974. if (connack_view->shared_subscriptions_available != NULL) {
  975. AWS_LOGUF(
  976. log_handle,
  977. level,
  978. AWS_LS_MQTT5_GENERAL,
  979. "id=%p: aws_mqtt5_packet_connack_view shared subscriptions available set to %d",
  980. (void *)connack_view,
  981. (int)(*connack_view->shared_subscriptions_available));
  982. }
  983. if (connack_view->server_keep_alive != NULL) {
  984. AWS_LOGUF(
  985. log_handle,
  986. level,
  987. AWS_LS_MQTT5_GENERAL,
  988. "id=%p: aws_mqtt5_packet_connack_view server keep alive set to %" PRIu16,
  989. (void *)connack_view,
  990. *connack_view->server_keep_alive);
  991. }
  992. if (connack_view->response_information != NULL) {
  993. AWS_LOGUF(
  994. log_handle,
  995. level,
  996. AWS_LS_MQTT5_GENERAL,
  997. "id=%p: aws_mqtt5_packet_connack_view response information set to \"" PRInSTR "\"",
  998. (void *)connack_view,
  999. AWS_BYTE_CURSOR_PRI(*connack_view->response_information));
  1000. }
  1001. if (connack_view->server_reference != NULL) {
  1002. AWS_LOGUF(
  1003. log_handle,
  1004. level,
  1005. AWS_LS_MQTT5_GENERAL,
  1006. "id=%p: aws_mqtt5_packet_connack_view server reference set to \"" PRInSTR "\"",
  1007. (void *)connack_view,
  1008. AWS_BYTE_CURSOR_PRI(*connack_view->server_reference));
  1009. }
  1010. if (connack_view->authentication_method != NULL) {
  1011. AWS_LOGUF(
  1012. log_handle,
  1013. level,
  1014. AWS_LS_MQTT5_GENERAL,
  1015. "id=%p: aws_mqtt5_packet_connack_view authentication method set",
  1016. (void *)connack_view);
  1017. }
  1018. if (connack_view->authentication_data != NULL) {
  1019. AWS_LOGUF(
  1020. log_handle,
  1021. level,
  1022. AWS_LS_MQTT5_GENERAL,
  1023. "id=%p: aws_mqtt5_packet_connack_view authentication data set",
  1024. (void *)connack_view);
  1025. }
  1026. s_aws_mqtt5_user_property_set_log(
  1027. log_handle,
  1028. connack_view->user_properties,
  1029. connack_view->user_property_count,
  1030. (void *)connack_view,
  1031. level,
  1032. "aws_mqtt5_packet_connack_view");
  1033. }
  1034. /*********************************************************************************************************************
  1035. * Disconnect
  1036. ********************************************************************************************************************/
  1037. int aws_mqtt5_packet_disconnect_view_validate(const struct aws_mqtt5_packet_disconnect_view *disconnect_view) {
  1038. if (disconnect_view == NULL) {
  1039. AWS_LOGF_ERROR(AWS_LS_MQTT5_GENERAL, "null DISCONNECT packet options");
  1040. return aws_raise_error(AWS_ERROR_INVALID_ARGUMENT);
  1041. }
  1042. bool is_valid_reason_code = true;
  1043. aws_mqtt5_disconnect_reason_code_to_c_string(disconnect_view->reason_code, &is_valid_reason_code);
  1044. if (!is_valid_reason_code) {
  1045. AWS_LOGF_ERROR(
  1046. AWS_LS_MQTT5_GENERAL,
  1047. "id=%p: aws_mqtt5_packet_disconnect_view - invalid DISCONNECT reason code:%d",
  1048. (void *)disconnect_view,
  1049. (int)disconnect_view->reason_code);
  1050. return aws_raise_error(AWS_ERROR_MQTT5_DISCONNECT_OPTIONS_VALIDATION);
  1051. }
  1052. if (disconnect_view->reason_string != NULL) {
  1053. if (disconnect_view->reason_string->len > UINT16_MAX) {
  1054. AWS_LOGF_ERROR(
  1055. AWS_LS_MQTT5_GENERAL,
  1056. "id=%p: aws_mqtt5_packet_disconnect_view - reason string too long",
  1057. (void *)disconnect_view);
  1058. return aws_raise_error(AWS_ERROR_MQTT5_DISCONNECT_OPTIONS_VALIDATION);
  1059. }
  1060. if (aws_mqtt5_validate_utf8_text(*disconnect_view->reason_string)) {
  1061. AWS_LOGF_ERROR(
  1062. AWS_LS_MQTT5_GENERAL,
  1063. "id=%p: aws_mqtt5_packet_disconnect_view - reason string not valid UTF-8",
  1064. (void *)disconnect_view);
  1065. return aws_raise_error(AWS_ERROR_MQTT5_DISCONNECT_OPTIONS_VALIDATION);
  1066. }
  1067. }
  1068. if (disconnect_view->server_reference != NULL) {
  1069. AWS_LOGF_ERROR(
  1070. AWS_LS_MQTT5_GENERAL,
  1071. "id=%p: aws_mqtt5_packet_disconnect_view - sending a server reference with a client-sourced DISCONNECT is "
  1072. "not allowed",
  1073. (void *)disconnect_view);
  1074. return aws_raise_error(AWS_ERROR_MQTT5_DISCONNECT_OPTIONS_VALIDATION);
  1075. }
  1076. if (s_aws_mqtt5_user_property_set_validate(
  1077. disconnect_view->user_properties,
  1078. disconnect_view->user_property_count,
  1079. "aws_mqtt5_packet_disconnect_view",
  1080. (void *)disconnect_view)) {
  1081. return AWS_OP_ERR;
  1082. }
  1083. return AWS_OP_SUCCESS;
  1084. }
  1085. static int s_aws_mqtt5_packet_disconnect_view_validate_vs_connection_settings(
  1086. const void *packet_view,
  1087. const struct aws_mqtt5_client *client) {
  1088. const struct aws_mqtt5_packet_disconnect_view *disconnect_view = packet_view;
  1089. if (disconnect_view->session_expiry_interval_seconds != NULL) {
  1090. /*
  1091. * By spec (https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901211), you
  1092. * cannot set a non-zero value here if you sent a 0-value or no value in the CONNECT (presumably allows
  1093. * the server to skip tracking session state, and we can't undo that now)
  1094. */
  1095. const uint32_t *session_expiry_ptr = client->config->connect.storage_view.session_expiry_interval_seconds;
  1096. if (*disconnect_view->session_expiry_interval_seconds > 0 &&
  1097. (session_expiry_ptr == NULL || *session_expiry_ptr == 0)) {
  1098. AWS_LOGF_ERROR(
  1099. AWS_LS_MQTT5_GENERAL,
  1100. "id=%p: aws_mqtt5_packet_disconnect_view - cannot specify a positive session expiry after "
  1101. "committing "
  1102. "to 0-valued session expiry in CONNECT",
  1103. (void *)disconnect_view);
  1104. return aws_raise_error(AWS_ERROR_MQTT5_DISCONNECT_OPTIONS_VALIDATION);
  1105. }
  1106. }
  1107. return AWS_OP_SUCCESS;
  1108. }
  1109. void aws_mqtt5_packet_disconnect_view_log(
  1110. const struct aws_mqtt5_packet_disconnect_view *disconnect_view,
  1111. enum aws_log_level level) {
  1112. struct aws_logger *log_handle = aws_logger_get_conditional(AWS_LS_MQTT5_GENERAL, level);
  1113. if (log_handle == NULL) {
  1114. return;
  1115. }
  1116. AWS_LOGUF(
  1117. log_handle,
  1118. level,
  1119. AWS_LS_MQTT5_GENERAL,
  1120. "id=%p: aws_mqtt5_packet_disconnect_view reason code set to %d (%s)",
  1121. (void *)disconnect_view,
  1122. (int)disconnect_view->reason_code,
  1123. aws_mqtt5_disconnect_reason_code_to_c_string(disconnect_view->reason_code, NULL));
  1124. if (disconnect_view->session_expiry_interval_seconds != NULL) {
  1125. AWS_LOGUF(
  1126. log_handle,
  1127. level,
  1128. AWS_LS_MQTT5_GENERAL,
  1129. "id=%p: aws_mqtt5_packet_disconnect_view session expiry interval set to %" PRIu32,
  1130. (void *)disconnect_view,
  1131. *disconnect_view->session_expiry_interval_seconds);
  1132. }
  1133. if (disconnect_view->reason_string != NULL) {
  1134. AWS_LOGUF(
  1135. log_handle,
  1136. level,
  1137. AWS_LS_MQTT5_GENERAL,
  1138. "id=%p: aws_mqtt5_packet_disconnect_view reason string set to \"" PRInSTR "\"",
  1139. (void *)disconnect_view,
  1140. AWS_BYTE_CURSOR_PRI(*disconnect_view->reason_string));
  1141. }
  1142. if (disconnect_view->server_reference != NULL) {
  1143. AWS_LOGUF(
  1144. log_handle,
  1145. level,
  1146. AWS_LS_MQTT5_GENERAL,
  1147. "id=%p: aws_mqtt5_packet_disconnect_view server reference set to \"" PRInSTR "\"",
  1148. (void *)disconnect_view,
  1149. AWS_BYTE_CURSOR_PRI(*disconnect_view->server_reference));
  1150. }
  1151. s_aws_mqtt5_user_property_set_log(
  1152. log_handle,
  1153. disconnect_view->user_properties,
  1154. disconnect_view->user_property_count,
  1155. (void *)disconnect_view,
  1156. level,
  1157. "aws_mqtt5_packet_disconnect_view");
  1158. }
  1159. void aws_mqtt5_packet_disconnect_storage_clean_up(struct aws_mqtt5_packet_disconnect_storage *disconnect_storage) {
  1160. if (disconnect_storage == NULL) {
  1161. return;
  1162. }
  1163. aws_mqtt5_user_property_set_clean_up(&disconnect_storage->user_properties);
  1164. aws_byte_buf_clean_up(&disconnect_storage->storage);
  1165. }
  1166. static size_t s_aws_mqtt5_packet_disconnect_compute_storage_size(
  1167. const struct aws_mqtt5_packet_disconnect_view *disconnect_view) {
  1168. size_t storage_size = s_aws_mqtt5_user_property_set_compute_storage_size(
  1169. disconnect_view->user_properties, disconnect_view->user_property_count);
  1170. if (disconnect_view->reason_string != NULL) {
  1171. storage_size += disconnect_view->reason_string->len;
  1172. }
  1173. if (disconnect_view->server_reference != NULL) {
  1174. storage_size += disconnect_view->server_reference->len;
  1175. }
  1176. return storage_size;
  1177. }
  1178. int aws_mqtt5_packet_disconnect_storage_init(
  1179. struct aws_mqtt5_packet_disconnect_storage *disconnect_storage,
  1180. struct aws_allocator *allocator,
  1181. const struct aws_mqtt5_packet_disconnect_view *disconnect_options) {
  1182. AWS_ZERO_STRUCT(*disconnect_storage);
  1183. size_t storage_capacity = s_aws_mqtt5_packet_disconnect_compute_storage_size(disconnect_options);
  1184. if (aws_byte_buf_init(&disconnect_storage->storage, allocator, storage_capacity)) {
  1185. return AWS_OP_ERR;
  1186. }
  1187. struct aws_mqtt5_packet_disconnect_view *storage_view = &disconnect_storage->storage_view;
  1188. storage_view->reason_code = disconnect_options->reason_code;
  1189. if (disconnect_options->session_expiry_interval_seconds != NULL) {
  1190. disconnect_storage->session_expiry_interval_seconds = *disconnect_options->session_expiry_interval_seconds;
  1191. storage_view->session_expiry_interval_seconds = &disconnect_storage->session_expiry_interval_seconds;
  1192. }
  1193. if (disconnect_options->reason_string != NULL) {
  1194. disconnect_storage->reason_string = *disconnect_options->reason_string;
  1195. if (aws_byte_buf_append_and_update(&disconnect_storage->storage, &disconnect_storage->reason_string)) {
  1196. return AWS_OP_ERR;
  1197. }
  1198. storage_view->reason_string = &disconnect_storage->reason_string;
  1199. }
  1200. if (disconnect_options->server_reference != NULL) {
  1201. disconnect_storage->server_reference = *disconnect_options->server_reference;
  1202. if (aws_byte_buf_append_and_update(&disconnect_storage->storage, &disconnect_storage->server_reference)) {
  1203. return AWS_OP_ERR;
  1204. }
  1205. storage_view->server_reference = &disconnect_storage->server_reference;
  1206. }
  1207. if (aws_mqtt5_user_property_set_init_with_storage(
  1208. &disconnect_storage->user_properties,
  1209. allocator,
  1210. &disconnect_storage->storage,
  1211. disconnect_options->user_property_count,
  1212. disconnect_options->user_properties)) {
  1213. return AWS_OP_ERR;
  1214. }
  1215. storage_view->user_property_count = aws_mqtt5_user_property_set_size(&disconnect_storage->user_properties);
  1216. storage_view->user_properties = disconnect_storage->user_properties.properties.data;
  1217. return AWS_OP_SUCCESS;
  1218. }
  1219. int aws_mqtt5_packet_disconnect_storage_init_from_external_storage(
  1220. struct aws_mqtt5_packet_disconnect_storage *disconnect_storage,
  1221. struct aws_allocator *allocator) {
  1222. AWS_ZERO_STRUCT(*disconnect_storage);
  1223. if (aws_mqtt5_user_property_set_init(&disconnect_storage->user_properties, allocator)) {
  1224. return AWS_OP_ERR;
  1225. }
  1226. return AWS_OP_SUCCESS;
  1227. }
  1228. static void s_destroy_operation_disconnect(void *object) {
  1229. if (object == NULL) {
  1230. return;
  1231. }
  1232. struct aws_mqtt5_operation_disconnect *disconnect_op = object;
  1233. aws_mqtt5_packet_disconnect_storage_clean_up(&disconnect_op->options_storage);
  1234. aws_mem_release(disconnect_op->allocator, disconnect_op);
  1235. }
  1236. static void s_aws_mqtt5_disconnect_operation_completion(
  1237. struct aws_mqtt5_operation *operation,
  1238. int error_code,
  1239. enum aws_mqtt5_packet_type packet_type,
  1240. const void *completion_view) {
  1241. (void)completion_view;
  1242. (void)packet_type;
  1243. struct aws_mqtt5_operation_disconnect *disconnect_op = operation->impl;
  1244. if (disconnect_op->internal_completion_options.completion_callback != NULL) {
  1245. (*disconnect_op->internal_completion_options.completion_callback)(
  1246. error_code, disconnect_op->internal_completion_options.completion_user_data);
  1247. }
  1248. if (disconnect_op->external_completion_options.completion_callback != NULL) {
  1249. (*disconnect_op->external_completion_options.completion_callback)(
  1250. error_code, disconnect_op->external_completion_options.completion_user_data);
  1251. }
  1252. }
  1253. static struct aws_mqtt5_operation_vtable s_disconnect_operation_vtable = {
  1254. .aws_mqtt5_operation_completion_fn = s_aws_mqtt5_disconnect_operation_completion,
  1255. .aws_mqtt5_operation_set_packet_id_fn = NULL,
  1256. .aws_mqtt5_operation_get_packet_id_address_fn = NULL,
  1257. .aws_mqtt5_operation_validate_vs_connection_settings_fn =
  1258. s_aws_mqtt5_packet_disconnect_view_validate_vs_connection_settings,
  1259. };
  1260. struct aws_mqtt5_operation_disconnect *aws_mqtt5_operation_disconnect_new(
  1261. struct aws_allocator *allocator,
  1262. const struct aws_mqtt5_packet_disconnect_view *disconnect_options,
  1263. const struct aws_mqtt5_disconnect_completion_options *external_completion_options,
  1264. const struct aws_mqtt5_disconnect_completion_options *internal_completion_options) {
  1265. AWS_PRECONDITION(allocator != NULL);
  1266. if (aws_mqtt5_packet_disconnect_view_validate(disconnect_options)) {
  1267. return NULL;
  1268. }
  1269. struct aws_mqtt5_operation_disconnect *disconnect_op =
  1270. aws_mem_calloc(allocator, 1, sizeof(struct aws_mqtt5_operation_disconnect));
  1271. if (disconnect_op == NULL) {
  1272. return NULL;
  1273. }
  1274. disconnect_op->allocator = allocator;
  1275. disconnect_op->base.vtable = &s_disconnect_operation_vtable;
  1276. disconnect_op->base.packet_type = AWS_MQTT5_PT_DISCONNECT;
  1277. aws_ref_count_init(&disconnect_op->base.ref_count, disconnect_op, s_destroy_operation_disconnect);
  1278. disconnect_op->base.impl = disconnect_op;
  1279. if (aws_mqtt5_packet_disconnect_storage_init(&disconnect_op->options_storage, allocator, disconnect_options)) {
  1280. goto error;
  1281. }
  1282. disconnect_op->base.packet_view = &disconnect_op->options_storage.storage_view;
  1283. if (external_completion_options != NULL) {
  1284. disconnect_op->external_completion_options = *external_completion_options;
  1285. }
  1286. if (internal_completion_options != NULL) {
  1287. disconnect_op->internal_completion_options = *internal_completion_options;
  1288. }
  1289. return disconnect_op;
  1290. error:
  1291. aws_mqtt5_operation_release(&disconnect_op->base);
  1292. return NULL;
  1293. }
  1294. /*********************************************************************************************************************
  1295. * Publish
  1296. ********************************************************************************************************************/
  1297. int aws_mqtt5_packet_publish_view_validate(const struct aws_mqtt5_packet_publish_view *publish_view) {
  1298. if (publish_view == NULL) {
  1299. AWS_LOGF_ERROR(AWS_LS_MQTT5_GENERAL, "null PUBLISH packet options");
  1300. return aws_raise_error(AWS_ERROR_INVALID_ARGUMENT);
  1301. }
  1302. if (publish_view->qos < AWS_MQTT5_QOS_AT_MOST_ONCE || publish_view->qos > AWS_MQTT5_QOS_EXACTLY_ONCE) {
  1303. AWS_LOGF_ERROR(
  1304. AWS_LS_MQTT5_GENERAL,
  1305. "id=%p: aws_mqtt5_packet_publish_view - unsupported QoS value in PUBLISH packet options: %d",
  1306. (void *)publish_view,
  1307. (int)publish_view->qos);
  1308. return aws_raise_error(AWS_ERROR_MQTT5_PUBLISH_OPTIONS_VALIDATION);
  1309. }
  1310. if (publish_view->qos == AWS_MQTT5_QOS_AT_MOST_ONCE) {
  1311. if (publish_view->duplicate) {
  1312. AWS_LOGF_ERROR(
  1313. AWS_LS_MQTT5_GENERAL,
  1314. "id=%p: aws_mqtt5_packet_publish_view - duplicate flag must be set to 0 for QoS 0 messages",
  1315. (void *)publish_view);
  1316. return aws_raise_error(AWS_ERROR_MQTT5_PUBLISH_OPTIONS_VALIDATION);
  1317. }
  1318. if (publish_view->packet_id != 0) {
  1319. AWS_LOGF_ERROR(
  1320. AWS_LS_MQTT5_GENERAL,
  1321. "id=%p: aws_mqtt5_packet_publish_view - Packet ID must not be set for QoS 0 messages",
  1322. (void *)publish_view);
  1323. return aws_raise_error(AWS_ERROR_MQTT5_PUBLISH_OPTIONS_VALIDATION);
  1324. }
  1325. }
  1326. /* 0-length topic is never valid, even with user-controlled outbound aliasing */
  1327. if (publish_view->topic.len == 0) {
  1328. AWS_LOGF_ERROR(
  1329. AWS_LS_MQTT5_GENERAL, "id=%p: aws_mqtt5_packet_publish_view - missing topic", (void *)publish_view);
  1330. return aws_raise_error(AWS_ERROR_MQTT5_PUBLISH_OPTIONS_VALIDATION);
  1331. } else if (aws_mqtt5_validate_utf8_text(publish_view->topic)) {
  1332. AWS_LOGF_ERROR(
  1333. AWS_LS_MQTT5_GENERAL, "id=%p: aws_mqtt5_packet_publish_view - topic not valid UTF-8", (void *)publish_view);
  1334. return aws_raise_error(AWS_ERROR_MQTT5_PUBLISH_OPTIONS_VALIDATION);
  1335. } else if (!aws_mqtt_is_valid_topic(&publish_view->topic)) {
  1336. AWS_LOGF_ERROR(
  1337. AWS_LS_MQTT5_GENERAL,
  1338. "id=%p: aws_mqtt5_packet_publish_view - invalid topic: \"" PRInSTR "\"",
  1339. (void *)publish_view,
  1340. AWS_BYTE_CURSOR_PRI(publish_view->topic));
  1341. return aws_raise_error(AWS_ERROR_MQTT5_PUBLISH_OPTIONS_VALIDATION);
  1342. }
  1343. if (publish_view->topic_alias != NULL) {
  1344. if (*publish_view->topic_alias == 0) {
  1345. AWS_LOGF_ERROR(
  1346. AWS_LS_MQTT5_GENERAL,
  1347. "id=%p: aws_mqtt5_packet_publish_view - topic alias may not be zero",
  1348. (void *)publish_view);
  1349. return aws_raise_error(AWS_ERROR_MQTT5_PUBLISH_OPTIONS_VALIDATION);
  1350. }
  1351. }
  1352. if (publish_view->payload_format != NULL) {
  1353. if (*publish_view->payload_format < AWS_MQTT5_PFI_BYTES || *publish_view->payload_format > AWS_MQTT5_PFI_UTF8) {
  1354. AWS_LOGF_ERROR(
  1355. AWS_LS_MQTT5_GENERAL,
  1356. "id=%p: aws_mqtt5_packet_publish_view - invalid payload format value: %d",
  1357. (void *)publish_view,
  1358. (int)*publish_view->payload_format);
  1359. return aws_raise_error(AWS_ERROR_MQTT5_PUBLISH_OPTIONS_VALIDATION);
  1360. }
  1361. // Make sure the payload data is UTF-8 if the payload_format set to UTF8
  1362. if (*publish_view->payload_format == AWS_MQTT5_PFI_UTF8) {
  1363. if (aws_mqtt5_validate_utf8_text(publish_view->payload)) {
  1364. AWS_LOGF_ERROR(
  1365. AWS_LS_MQTT5_GENERAL,
  1366. "id=%p: aws_mqtt5_packet_publish_view - payload value is not valid UTF-8 while payload format "
  1367. "set to UTF-8",
  1368. (void *)publish_view);
  1369. return aws_raise_error(AWS_ERROR_MQTT5_PUBLISH_OPTIONS_VALIDATION);
  1370. }
  1371. }
  1372. }
  1373. if (publish_view->response_topic != NULL) {
  1374. if (publish_view->response_topic->len >= UINT16_MAX) {
  1375. AWS_LOGF_ERROR(
  1376. AWS_LS_MQTT5_GENERAL,
  1377. "id=%p: aws_mqtt5_packet_publish_view - response topic too long",
  1378. (void *)publish_view);
  1379. return aws_raise_error(AWS_ERROR_MQTT5_PUBLISH_OPTIONS_VALIDATION);
  1380. }
  1381. if (aws_mqtt5_validate_utf8_text(*publish_view->response_topic)) {
  1382. AWS_LOGF_ERROR(
  1383. AWS_LS_MQTT5_GENERAL,
  1384. "id=%p: aws_mqtt5_packet_publish_view - response topic not valid UTF-8",
  1385. (void *)publish_view);
  1386. return aws_raise_error(AWS_ERROR_MQTT5_PUBLISH_OPTIONS_VALIDATION);
  1387. }
  1388. if (!aws_mqtt_is_valid_topic(publish_view->response_topic)) {
  1389. AWS_LOGF_ERROR(
  1390. AWS_LS_MQTT5_GENERAL,
  1391. "id=%p: aws_mqtt5_packet_publish_view - response topic must be a valid mqtt topic",
  1392. (void *)publish_view);
  1393. return aws_raise_error(AWS_ERROR_MQTT5_PUBLISH_OPTIONS_VALIDATION);
  1394. }
  1395. }
  1396. if (publish_view->correlation_data != NULL) {
  1397. if (publish_view->correlation_data->len >= UINT16_MAX) {
  1398. AWS_LOGF_ERROR(
  1399. AWS_LS_MQTT5_GENERAL,
  1400. "id=%p: aws_mqtt5_packet_publish_view - correlation data too long",
  1401. (void *)publish_view);
  1402. return aws_raise_error(AWS_ERROR_MQTT5_PUBLISH_OPTIONS_VALIDATION);
  1403. }
  1404. }
  1405. /*
  1406. * validate is done from a client perspective and clients should never generate subscription identifier in a
  1407. * publish message
  1408. */
  1409. if (publish_view->subscription_identifier_count != 0) {
  1410. AWS_LOGF_ERROR(
  1411. AWS_LS_MQTT5_GENERAL, "Client-initiated PUBLISH packets may not contain subscription identifiers");
  1412. return aws_raise_error(AWS_ERROR_MQTT5_PUBLISH_OPTIONS_VALIDATION);
  1413. }
  1414. if (publish_view->content_type != NULL) {
  1415. if (publish_view->content_type->len >= UINT16_MAX) {
  1416. AWS_LOGF_ERROR(
  1417. AWS_LS_MQTT5_GENERAL,
  1418. "id=%p: aws_mqtt5_packet_publish_view - content type too long",
  1419. (void *)publish_view);
  1420. return aws_raise_error(AWS_ERROR_MQTT5_PUBLISH_OPTIONS_VALIDATION);
  1421. }
  1422. if (aws_mqtt5_validate_utf8_text(*publish_view->content_type)) {
  1423. AWS_LOGF_ERROR(
  1424. AWS_LS_MQTT5_GENERAL,
  1425. "id=%p: aws_mqtt5_packet_publish_view - content type not valid UTF-8",
  1426. (void *)publish_view);
  1427. return aws_raise_error(AWS_ERROR_MQTT5_PUBLISH_OPTIONS_VALIDATION);
  1428. }
  1429. }
  1430. if (s_aws_mqtt5_user_property_set_validate(
  1431. publish_view->user_properties,
  1432. publish_view->user_property_count,
  1433. "aws_mqtt5_packet_publish_view",
  1434. (void *)publish_view)) {
  1435. return AWS_OP_ERR;
  1436. }
  1437. return AWS_OP_SUCCESS;
  1438. }
  1439. int aws_mqtt5_packet_publish_view_validate_vs_iot_core(const struct aws_mqtt5_packet_publish_view *publish_view) {
  1440. if (!aws_mqtt_is_valid_topic_for_iot_core(publish_view->topic)) {
  1441. AWS_LOGF_ERROR(
  1442. AWS_LS_MQTT5_GENERAL,
  1443. "id=%p: aws_mqtt5_packet_publish_view - topic not valid for AWS Iot Core limits: \"" PRInSTR "\"",
  1444. (void *)publish_view,
  1445. AWS_BYTE_CURSOR_PRI(publish_view->topic));
  1446. return AWS_OP_ERR;
  1447. }
  1448. return AWS_OP_SUCCESS;
  1449. }
  1450. static int s_aws_mqtt5_packet_publish_view_validate_vs_connection_settings(
  1451. const void *packet_view,
  1452. const struct aws_mqtt5_client *client) {
  1453. const struct aws_mqtt5_packet_publish_view *publish_view = packet_view;
  1454. /* If we have valid negotiated settings, check against them as well */
  1455. if (aws_mqtt5_client_are_negotiated_settings_valid(client)) {
  1456. const struct aws_mqtt5_negotiated_settings *settings = &client->negotiated_settings;
  1457. if (publish_view->qos > settings->maximum_qos) {
  1458. AWS_LOGF_ERROR(
  1459. AWS_LS_MQTT5_GENERAL,
  1460. "id=%p: aws_mqtt5_packet_publish_view - QoS value %d exceeds negotiated maximum qos %d",
  1461. (void *)publish_view,
  1462. (int)publish_view->qos,
  1463. (int)settings->maximum_qos);
  1464. return aws_raise_error(AWS_ERROR_MQTT5_PUBLISH_OPTIONS_VALIDATION);
  1465. }
  1466. if (publish_view->topic_alias != NULL) {
  1467. const struct aws_mqtt5_client_options_storage *client_options = client->config;
  1468. if (client_options->topic_aliasing_options.outbound_topic_alias_behavior != AWS_MQTT5_COTABT_USER) {
  1469. AWS_LOGF_ERROR(
  1470. AWS_LS_MQTT5_GENERAL,
  1471. "id=%p: aws_mqtt5_packet_publish_view - topic alias set but outbound topic alias behavior has not "
  1472. "been set to user controlled",
  1473. (void *)publish_view);
  1474. return aws_raise_error(AWS_ERROR_MQTT5_PUBLISH_OPTIONS_VALIDATION);
  1475. }
  1476. if (*publish_view->topic_alias > settings->topic_alias_maximum_to_server) {
  1477. AWS_LOGF_ERROR(
  1478. AWS_LS_MQTT5_GENERAL,
  1479. "id=%p: aws_mqtt5_packet_publish_view - outbound topic alias (%d) exceeds server's topic alias "
  1480. "maximum "
  1481. "(%d)",
  1482. (void *)publish_view,
  1483. (int)(*publish_view->topic_alias),
  1484. (int)settings->topic_alias_maximum_to_server);
  1485. return aws_raise_error(AWS_ERROR_MQTT5_PUBLISH_OPTIONS_VALIDATION);
  1486. }
  1487. }
  1488. if (publish_view->retain && settings->retain_available == false) {
  1489. AWS_LOGF_ERROR(
  1490. AWS_LS_MQTT5_GENERAL,
  1491. "id=%p: aws_mqtt5_packet_publish_view - server does not support Retain",
  1492. (void *)publish_view);
  1493. return aws_raise_error(AWS_ERROR_MQTT5_PUBLISH_OPTIONS_VALIDATION);
  1494. }
  1495. }
  1496. return AWS_OP_SUCCESS;
  1497. }
  1498. void aws_mqtt5_packet_publish_view_log(
  1499. const struct aws_mqtt5_packet_publish_view *publish_view,
  1500. enum aws_log_level level) {
  1501. struct aws_logger *log_handle = aws_logger_get_conditional(AWS_LS_MQTT5_GENERAL, level);
  1502. if (log_handle == NULL) {
  1503. return;
  1504. }
  1505. AWS_LOGUF(
  1506. log_handle,
  1507. level,
  1508. AWS_LS_MQTT5_GENERAL,
  1509. "id=%p: aws_mqtt5_packet_publish_view packet id set to %d",
  1510. (void *)publish_view,
  1511. (int)publish_view->packet_id);
  1512. AWS_LOGUF(
  1513. log_handle,
  1514. level,
  1515. AWS_LS_MQTT5_GENERAL,
  1516. "id=%p: aws_mqtt5_packet_publish_view payload set containing %zu bytes",
  1517. (void *)publish_view,
  1518. publish_view->payload.len);
  1519. AWS_LOGUF(
  1520. log_handle,
  1521. level,
  1522. AWS_LS_MQTT5_GENERAL,
  1523. "id=%p: aws_mqtt5_packet_publish_view qos set to %d",
  1524. (void *)publish_view,
  1525. (int)publish_view->qos);
  1526. AWS_LOGUF(
  1527. log_handle,
  1528. level,
  1529. AWS_LS_MQTT5_GENERAL,
  1530. "id=%p: aws_mqtt5_packet_publish_view retain set to %d",
  1531. (void *)publish_view,
  1532. (int)publish_view->retain);
  1533. AWS_LOGUF(
  1534. log_handle,
  1535. level,
  1536. AWS_LS_MQTT5_GENERAL,
  1537. "id=%p: aws_mqtt5_packet_publish_view topic set to \"" PRInSTR "\"",
  1538. (void *)publish_view,
  1539. AWS_BYTE_CURSOR_PRI(publish_view->topic));
  1540. if (publish_view->payload_format != NULL) {
  1541. AWS_LOGUF(
  1542. log_handle,
  1543. level,
  1544. AWS_LS_MQTT5_GENERAL,
  1545. "id=%p: aws_mqtt5_packet_publish_view payload format indicator set to %d (%s)",
  1546. (void *)publish_view,
  1547. (int)*publish_view->payload_format,
  1548. aws_mqtt5_payload_format_indicator_to_c_string(*publish_view->payload_format));
  1549. }
  1550. if (publish_view->message_expiry_interval_seconds != NULL) {
  1551. AWS_LOGUF(
  1552. log_handle,
  1553. level,
  1554. AWS_LS_MQTT5_GENERAL,
  1555. "id=%p: aws_mqtt5_packet_publish_view message expiry interval set to %" PRIu32,
  1556. (void *)publish_view,
  1557. *publish_view->message_expiry_interval_seconds);
  1558. }
  1559. if (publish_view->topic_alias != NULL) {
  1560. AWS_LOGUF(
  1561. log_handle,
  1562. level,
  1563. AWS_LS_MQTT5_GENERAL,
  1564. "id=%p: aws_mqtt5_packet_publish_view topic alias set to %" PRIu16,
  1565. (void *)publish_view,
  1566. *publish_view->topic_alias);
  1567. }
  1568. if (publish_view->response_topic != NULL) {
  1569. AWS_LOGUF(
  1570. log_handle,
  1571. level,
  1572. AWS_LS_MQTT5_GENERAL,
  1573. "id=%p: aws_mqtt5_packet_publish_view response topic set to \"" PRInSTR "\"",
  1574. (void *)publish_view,
  1575. AWS_BYTE_CURSOR_PRI(*publish_view->response_topic));
  1576. }
  1577. if (publish_view->correlation_data != NULL) {
  1578. AWS_LOGUF(
  1579. log_handle,
  1580. level,
  1581. AWS_LS_MQTT5_GENERAL,
  1582. "id=%p: aws_mqtt5_packet_publish_view - set correlation data",
  1583. (void *)publish_view);
  1584. }
  1585. if (publish_view->content_type != NULL) {
  1586. AWS_LOGUF(
  1587. log_handle,
  1588. level,
  1589. AWS_LS_MQTT5_GENERAL,
  1590. "id=%p: aws_mqtt5_packet_publish_view content type set to \"" PRInSTR "\"",
  1591. (void *)publish_view,
  1592. AWS_BYTE_CURSOR_PRI(*publish_view->content_type));
  1593. }
  1594. for (size_t i = 0; i < publish_view->subscription_identifier_count; ++i) {
  1595. AWS_LOGUF(
  1596. log_handle,
  1597. level,
  1598. AWS_LS_MQTT5_GENERAL,
  1599. "id=%p: aws_mqtt5_packet_publish_view subscription identifier %d: %" PRIu32,
  1600. (void *)publish_view,
  1601. (int)i,
  1602. publish_view->subscription_identifiers[i]);
  1603. }
  1604. s_aws_mqtt5_user_property_set_log(
  1605. log_handle,
  1606. publish_view->user_properties,
  1607. publish_view->user_property_count,
  1608. (void *)publish_view,
  1609. level,
  1610. "aws_mqtt5_packet_publish_view");
  1611. }
  1612. static size_t s_aws_mqtt5_packet_publish_compute_storage_size(
  1613. const struct aws_mqtt5_packet_publish_view *publish_view) {
  1614. size_t storage_size = s_aws_mqtt5_user_property_set_compute_storage_size(
  1615. publish_view->user_properties, publish_view->user_property_count);
  1616. storage_size += publish_view->topic.len;
  1617. storage_size += publish_view->payload.len;
  1618. if (publish_view->response_topic != NULL) {
  1619. storage_size += publish_view->response_topic->len;
  1620. }
  1621. if (publish_view->correlation_data != NULL) {
  1622. storage_size += publish_view->correlation_data->len;
  1623. }
  1624. if (publish_view->content_type != NULL) {
  1625. storage_size += publish_view->content_type->len;
  1626. }
  1627. return storage_size;
  1628. }
  1629. int aws_mqtt5_packet_publish_storage_init(
  1630. struct aws_mqtt5_packet_publish_storage *publish_storage,
  1631. struct aws_allocator *allocator,
  1632. const struct aws_mqtt5_packet_publish_view *publish_options) {
  1633. AWS_ZERO_STRUCT(*publish_storage);
  1634. size_t storage_capacity = s_aws_mqtt5_packet_publish_compute_storage_size(publish_options);
  1635. if (aws_byte_buf_init(&publish_storage->storage, allocator, storage_capacity)) {
  1636. return AWS_OP_ERR;
  1637. }
  1638. if (aws_array_list_init_dynamic(&publish_storage->subscription_identifiers, allocator, 0, sizeof(uint32_t))) {
  1639. return AWS_OP_ERR;
  1640. }
  1641. struct aws_mqtt5_packet_publish_view *storage_view = &publish_storage->storage_view;
  1642. storage_view->packet_id = publish_options->packet_id;
  1643. storage_view->payload = publish_options->payload;
  1644. if (aws_byte_buf_append_and_update(&publish_storage->storage, &storage_view->payload)) {
  1645. return AWS_OP_ERR;
  1646. }
  1647. storage_view->qos = publish_options->qos;
  1648. storage_view->retain = publish_options->retain;
  1649. storage_view->duplicate = publish_options->duplicate;
  1650. storage_view->topic = publish_options->topic;
  1651. if (aws_byte_buf_append_and_update(&publish_storage->storage, &storage_view->topic)) {
  1652. return AWS_OP_ERR;
  1653. }
  1654. if (publish_options->payload_format != NULL) {
  1655. publish_storage->payload_format = *publish_options->payload_format;
  1656. storage_view->payload_format = &publish_storage->payload_format;
  1657. }
  1658. if (publish_options->message_expiry_interval_seconds != NULL) {
  1659. publish_storage->message_expiry_interval_seconds = *publish_options->message_expiry_interval_seconds;
  1660. storage_view->message_expiry_interval_seconds = &publish_storage->message_expiry_interval_seconds;
  1661. }
  1662. if (publish_options->topic_alias != NULL) {
  1663. publish_storage->topic_alias = *publish_options->topic_alias;
  1664. storage_view->topic_alias = &publish_storage->topic_alias;
  1665. }
  1666. if (publish_options->response_topic != NULL) {
  1667. publish_storage->response_topic = *publish_options->response_topic;
  1668. if (aws_byte_buf_append_and_update(&publish_storage->storage, &publish_storage->response_topic)) {
  1669. return AWS_OP_ERR;
  1670. }
  1671. storage_view->response_topic = &publish_storage->response_topic;
  1672. }
  1673. if (publish_options->correlation_data != NULL) {
  1674. publish_storage->correlation_data = *publish_options->correlation_data;
  1675. if (aws_byte_buf_append_and_update(&publish_storage->storage, &publish_storage->correlation_data)) {
  1676. return AWS_OP_ERR;
  1677. }
  1678. storage_view->correlation_data = &publish_storage->correlation_data;
  1679. }
  1680. for (size_t i = 0; i < publish_options->subscription_identifier_count; ++i) {
  1681. aws_array_list_push_back(
  1682. &publish_storage->subscription_identifiers, &publish_options->subscription_identifiers[i]);
  1683. }
  1684. storage_view->subscription_identifier_count = aws_array_list_length(&publish_storage->subscription_identifiers);
  1685. storage_view->subscription_identifiers = publish_storage->subscription_identifiers.data;
  1686. if (publish_options->content_type != NULL) {
  1687. publish_storage->content_type = *publish_options->content_type;
  1688. if (aws_byte_buf_append_and_update(&publish_storage->storage, &publish_storage->content_type)) {
  1689. return AWS_OP_ERR;
  1690. }
  1691. storage_view->content_type = &publish_storage->content_type;
  1692. }
  1693. if (aws_mqtt5_user_property_set_init_with_storage(
  1694. &publish_storage->user_properties,
  1695. allocator,
  1696. &publish_storage->storage,
  1697. publish_options->user_property_count,
  1698. publish_options->user_properties)) {
  1699. return AWS_OP_ERR;
  1700. }
  1701. storage_view->user_property_count = aws_mqtt5_user_property_set_size(&publish_storage->user_properties);
  1702. storage_view->user_properties = publish_storage->user_properties.properties.data;
  1703. return AWS_OP_SUCCESS;
  1704. }
  1705. int aws_mqtt5_packet_publish_storage_init_from_external_storage(
  1706. struct aws_mqtt5_packet_publish_storage *publish_storage,
  1707. struct aws_allocator *allocator) {
  1708. AWS_ZERO_STRUCT(*publish_storage);
  1709. if (aws_mqtt5_user_property_set_init(&publish_storage->user_properties, allocator)) {
  1710. return AWS_OP_ERR;
  1711. }
  1712. if (aws_array_list_init_dynamic(&publish_storage->subscription_identifiers, allocator, 0, sizeof(uint32_t))) {
  1713. return AWS_OP_ERR;
  1714. }
  1715. return AWS_OP_SUCCESS;
  1716. }
  1717. void aws_mqtt5_packet_publish_storage_clean_up(struct aws_mqtt5_packet_publish_storage *publish_storage) {
  1718. aws_mqtt5_user_property_set_clean_up(&publish_storage->user_properties);
  1719. aws_array_list_clean_up(&publish_storage->subscription_identifiers);
  1720. aws_byte_buf_clean_up(&publish_storage->storage);
  1721. }
  1722. static void s_aws_mqtt5_operation_publish_complete(
  1723. struct aws_mqtt5_operation *operation,
  1724. int error_code,
  1725. enum aws_mqtt5_packet_type packet_type,
  1726. const void *completion_view) {
  1727. struct aws_mqtt5_operation_publish *publish_op = operation->impl;
  1728. if (publish_op->completion_options.completion_callback != NULL) {
  1729. (*publish_op->completion_options.completion_callback)(
  1730. packet_type, completion_view, error_code, publish_op->completion_options.completion_user_data);
  1731. }
  1732. }
  1733. static void s_aws_mqtt5_operation_publish_set_packet_id(
  1734. struct aws_mqtt5_operation *operation,
  1735. aws_mqtt5_packet_id_t packet_id) {
  1736. struct aws_mqtt5_operation_publish *publish_op = operation->impl;
  1737. publish_op->options_storage.storage_view.packet_id = packet_id;
  1738. }
  1739. static aws_mqtt5_packet_id_t *s_aws_mqtt5_operation_publish_get_packet_id_address(
  1740. const struct aws_mqtt5_operation *operation) {
  1741. struct aws_mqtt5_operation_publish *publish_op = operation->impl;
  1742. return &publish_op->options_storage.storage_view.packet_id;
  1743. }
  1744. static struct aws_mqtt5_operation_vtable s_publish_operation_vtable = {
  1745. .aws_mqtt5_operation_completion_fn = s_aws_mqtt5_operation_publish_complete,
  1746. .aws_mqtt5_operation_set_packet_id_fn = s_aws_mqtt5_operation_publish_set_packet_id,
  1747. .aws_mqtt5_operation_get_packet_id_address_fn = s_aws_mqtt5_operation_publish_get_packet_id_address,
  1748. .aws_mqtt5_operation_validate_vs_connection_settings_fn =
  1749. s_aws_mqtt5_packet_publish_view_validate_vs_connection_settings,
  1750. };
  1751. static void s_destroy_operation_publish(void *object) {
  1752. if (object == NULL) {
  1753. return;
  1754. }
  1755. struct aws_mqtt5_operation_publish *publish_op = object;
  1756. aws_mqtt5_packet_publish_storage_clean_up(&publish_op->options_storage);
  1757. aws_mem_release(publish_op->allocator, publish_op);
  1758. }
  1759. struct aws_mqtt5_operation_publish *aws_mqtt5_operation_publish_new(
  1760. struct aws_allocator *allocator,
  1761. const struct aws_mqtt5_client *client,
  1762. const struct aws_mqtt5_packet_publish_view *publish_options,
  1763. const struct aws_mqtt5_publish_completion_options *completion_options) {
  1764. AWS_PRECONDITION(allocator != NULL);
  1765. AWS_PRECONDITION(publish_options != NULL);
  1766. if (aws_mqtt5_packet_publish_view_validate(publish_options)) {
  1767. return NULL;
  1768. }
  1769. if (publish_options->packet_id != 0) {
  1770. AWS_LOGF_DEBUG(
  1771. AWS_LS_MQTT5_GENERAL,
  1772. "id=%p: aws_mqtt5_packet_publish_view packet id must be zero",
  1773. (void *)publish_options);
  1774. aws_raise_error(AWS_ERROR_MQTT5_PUBLISH_OPTIONS_VALIDATION);
  1775. return NULL;
  1776. }
  1777. if (client != NULL && client->config->extended_validation_and_flow_control_options != AWS_MQTT5_EVAFCO_NONE) {
  1778. if (aws_mqtt5_packet_publish_view_validate_vs_iot_core(publish_options)) {
  1779. return NULL;
  1780. }
  1781. }
  1782. struct aws_mqtt5_operation_publish *publish_op =
  1783. aws_mem_calloc(allocator, 1, sizeof(struct aws_mqtt5_operation_publish));
  1784. if (publish_op == NULL) {
  1785. return NULL;
  1786. }
  1787. publish_op->allocator = allocator;
  1788. publish_op->base.vtable = &s_publish_operation_vtable;
  1789. publish_op->base.packet_type = AWS_MQTT5_PT_PUBLISH;
  1790. aws_ref_count_init(&publish_op->base.ref_count, publish_op, s_destroy_operation_publish);
  1791. publish_op->base.impl = publish_op;
  1792. if (aws_mqtt5_packet_publish_storage_init(&publish_op->options_storage, allocator, publish_options)) {
  1793. goto error;
  1794. }
  1795. publish_op->base.packet_view = &publish_op->options_storage.storage_view;
  1796. if (completion_options != NULL) {
  1797. publish_op->completion_options = *completion_options;
  1798. }
  1799. return publish_op;
  1800. error:
  1801. aws_mqtt5_operation_release(&publish_op->base);
  1802. return NULL;
  1803. }
  1804. /*********************************************************************************************************************
  1805. * Puback
  1806. ********************************************************************************************************************/
  1807. static size_t s_aws_mqtt5_packet_puback_compute_storage_size(const struct aws_mqtt5_packet_puback_view *puback_view) {
  1808. size_t storage_size = s_aws_mqtt5_user_property_set_compute_storage_size(
  1809. puback_view->user_properties, puback_view->user_property_count);
  1810. if (puback_view->reason_string != NULL) {
  1811. storage_size += puback_view->reason_string->len;
  1812. }
  1813. return storage_size;
  1814. }
  1815. AWS_MQTT_API int aws_mqtt5_packet_puback_storage_init(
  1816. struct aws_mqtt5_packet_puback_storage *puback_storage,
  1817. struct aws_allocator *allocator,
  1818. const struct aws_mqtt5_packet_puback_view *puback_view) {
  1819. AWS_ZERO_STRUCT(*puback_storage);
  1820. size_t storage_capacity = s_aws_mqtt5_packet_puback_compute_storage_size(puback_view);
  1821. if (aws_byte_buf_init(&puback_storage->storage, allocator, storage_capacity)) {
  1822. return AWS_OP_ERR;
  1823. }
  1824. struct aws_mqtt5_packet_puback_view *storage_view = &puback_storage->storage_view;
  1825. storage_view->packet_id = puback_view->packet_id;
  1826. storage_view->reason_code = puback_view->reason_code;
  1827. if (puback_view->reason_string != NULL) {
  1828. puback_storage->reason_string = *puback_view->reason_string;
  1829. if (aws_byte_buf_append_and_update(&puback_storage->storage, &puback_storage->reason_string)) {
  1830. return AWS_OP_ERR;
  1831. }
  1832. storage_view->reason_string = &puback_storage->reason_string;
  1833. }
  1834. if (aws_mqtt5_user_property_set_init_with_storage(
  1835. &puback_storage->user_properties,
  1836. allocator,
  1837. &puback_storage->storage,
  1838. puback_view->user_property_count,
  1839. puback_view->user_properties)) {
  1840. return AWS_OP_ERR;
  1841. }
  1842. storage_view->user_property_count = aws_mqtt5_user_property_set_size(&puback_storage->user_properties);
  1843. storage_view->user_properties = puback_storage->user_properties.properties.data;
  1844. return AWS_OP_SUCCESS;
  1845. }
  1846. int aws_mqtt5_packet_puback_storage_init_from_external_storage(
  1847. struct aws_mqtt5_packet_puback_storage *puback_storage,
  1848. struct aws_allocator *allocator) {
  1849. AWS_ZERO_STRUCT(*puback_storage);
  1850. if (aws_mqtt5_user_property_set_init(&puback_storage->user_properties, allocator)) {
  1851. return AWS_OP_ERR;
  1852. }
  1853. return AWS_OP_SUCCESS;
  1854. }
  1855. void aws_mqtt5_packet_puback_storage_clean_up(struct aws_mqtt5_packet_puback_storage *puback_storage) {
  1856. if (puback_storage == NULL) {
  1857. return;
  1858. }
  1859. aws_mqtt5_user_property_set_clean_up(&puback_storage->user_properties);
  1860. aws_byte_buf_clean_up(&puback_storage->storage);
  1861. }
  1862. void aws_mqtt5_packet_puback_view_log(
  1863. const struct aws_mqtt5_packet_puback_view *puback_view,
  1864. enum aws_log_level level) {
  1865. struct aws_logger *log_handle = aws_logger_get_conditional(AWS_LS_MQTT5_GENERAL, level);
  1866. if (log_handle == NULL) {
  1867. return;
  1868. }
  1869. AWS_LOGUF(
  1870. log_handle,
  1871. level,
  1872. AWS_LS_MQTT5_GENERAL,
  1873. "id=%p: aws_mqtt5_packet_puback_view packet id set to %d",
  1874. (void *)puback_view,
  1875. (int)puback_view->packet_id);
  1876. enum aws_mqtt5_puback_reason_code reason_code = puback_view->reason_code;
  1877. AWS_LOGUF(
  1878. log_handle,
  1879. level,
  1880. AWS_LS_MQTT5_GENERAL,
  1881. "id=%p: puback %d reason code: %s",
  1882. (void *)puback_view,
  1883. (int)reason_code,
  1884. aws_mqtt5_puback_reason_code_to_c_string(reason_code));
  1885. if (puback_view->reason_string != NULL) {
  1886. AWS_LOGUF(
  1887. log_handle,
  1888. level,
  1889. AWS_LS_MQTT5_GENERAL,
  1890. "id=%p: aws_mqtt5_packet_puback_view reason string set to \"" PRInSTR "\"",
  1891. (void *)puback_view,
  1892. AWS_BYTE_CURSOR_PRI(*puback_view->reason_string));
  1893. }
  1894. s_aws_mqtt5_user_property_set_log(
  1895. log_handle,
  1896. puback_view->user_properties,
  1897. puback_view->user_property_count,
  1898. (void *)puback_view,
  1899. level,
  1900. "aws_mqtt5_packet_puback_view");
  1901. }
  1902. static void s_destroy_operation_puback(void *object) {
  1903. if (object == NULL) {
  1904. return;
  1905. }
  1906. struct aws_mqtt5_operation_puback *puback_op = object;
  1907. aws_mqtt5_packet_puback_storage_clean_up(&puback_op->options_storage);
  1908. aws_mem_release(puback_op->allocator, puback_op);
  1909. }
  1910. struct aws_mqtt5_operation_puback *aws_mqtt5_operation_puback_new(
  1911. struct aws_allocator *allocator,
  1912. const struct aws_mqtt5_packet_puback_view *puback_options) {
  1913. AWS_PRECONDITION(allocator != NULL);
  1914. AWS_PRECONDITION(puback_options != NULL);
  1915. struct aws_mqtt5_operation_puback *puback_op =
  1916. aws_mem_calloc(allocator, 1, sizeof(struct aws_mqtt5_operation_puback));
  1917. if (puback_op == NULL) {
  1918. return NULL;
  1919. }
  1920. puback_op->allocator = allocator;
  1921. puback_op->base.vtable = &s_empty_operation_vtable;
  1922. puback_op->base.packet_type = AWS_MQTT5_PT_PUBACK;
  1923. aws_ref_count_init(&puback_op->base.ref_count, puback_op, s_destroy_operation_puback);
  1924. puback_op->base.impl = puback_op;
  1925. if (aws_mqtt5_packet_puback_storage_init(&puback_op->options_storage, allocator, puback_options)) {
  1926. goto error;
  1927. }
  1928. puback_op->base.packet_view = &puback_op->options_storage.storage_view;
  1929. return puback_op;
  1930. error:
  1931. aws_mqtt5_operation_release(&puback_op->base);
  1932. return NULL;
  1933. }
  1934. /*********************************************************************************************************************
  1935. * Unsubscribe
  1936. ********************************************************************************************************************/
  1937. int aws_mqtt5_packet_unsubscribe_view_validate(const struct aws_mqtt5_packet_unsubscribe_view *unsubscribe_view) {
  1938. if (unsubscribe_view == NULL) {
  1939. AWS_LOGF_ERROR(AWS_LS_MQTT5_GENERAL, "null UNSUBSCRIBE packet options");
  1940. return aws_raise_error(AWS_ERROR_INVALID_ARGUMENT);
  1941. }
  1942. if (unsubscribe_view->topic_filter_count == 0) {
  1943. AWS_LOGF_ERROR(
  1944. AWS_LS_MQTT5_GENERAL,
  1945. "id=%p: aws_mqtt5_packet_unsubscribe_view - must contain at least one topic",
  1946. (void *)unsubscribe_view);
  1947. return aws_raise_error(AWS_ERROR_MQTT5_UNSUBSCRIBE_OPTIONS_VALIDATION);
  1948. }
  1949. if (unsubscribe_view->topic_filter_count > AWS_MQTT5_CLIENT_MAXIMUM_TOPIC_FILTERS_PER_UNSUBSCRIBE) {
  1950. AWS_LOGF_ERROR(
  1951. AWS_LS_MQTT5_GENERAL,
  1952. "id=%p: aws_mqtt5_packet_unsubscribe_view - contains too many topics (%zu)",
  1953. (void *)unsubscribe_view,
  1954. unsubscribe_view->topic_filter_count);
  1955. return aws_raise_error(AWS_ERROR_MQTT5_UNSUBSCRIBE_OPTIONS_VALIDATION);
  1956. }
  1957. for (size_t i = 0; i < unsubscribe_view->topic_filter_count; ++i) {
  1958. const struct aws_byte_cursor *topic_filter = &unsubscribe_view->topic_filters[i];
  1959. if (aws_mqtt5_validate_utf8_text(*topic_filter)) {
  1960. AWS_LOGF_ERROR(
  1961. AWS_LS_MQTT5_GENERAL,
  1962. "id=%p: aws_mqtt5_packet_unsubscribe_view - topic filter not valid UTF-8: \"" PRInSTR "\"",
  1963. (void *)unsubscribe_view,
  1964. AWS_BYTE_CURSOR_PRI(*topic_filter));
  1965. return aws_raise_error(AWS_ERROR_MQTT5_UNSUBSCRIBE_OPTIONS_VALIDATION);
  1966. }
  1967. if (!aws_mqtt_is_valid_topic_filter(topic_filter)) {
  1968. AWS_LOGF_ERROR(
  1969. AWS_LS_MQTT5_GENERAL,
  1970. "id=%p: aws_mqtt5_packet_unsubscribe_view - invalid topic filter: \"" PRInSTR "\"",
  1971. (void *)unsubscribe_view,
  1972. AWS_BYTE_CURSOR_PRI(*topic_filter));
  1973. return aws_raise_error(AWS_ERROR_MQTT5_UNSUBSCRIBE_OPTIONS_VALIDATION);
  1974. }
  1975. }
  1976. if (s_aws_mqtt5_user_property_set_validate(
  1977. unsubscribe_view->user_properties,
  1978. unsubscribe_view->user_property_count,
  1979. "aws_mqtt5_packet_unsubscribe_view",
  1980. (void *)unsubscribe_view)) {
  1981. return AWS_OP_ERR;
  1982. }
  1983. return AWS_OP_SUCCESS;
  1984. }
  1985. AWS_MQTT_API int aws_mqtt5_packet_unsubscribe_view_validate_vs_iot_core(
  1986. const struct aws_mqtt5_packet_unsubscribe_view *unsubscribe_view) {
  1987. for (size_t i = 0; i < unsubscribe_view->topic_filter_count; ++i) {
  1988. const struct aws_byte_cursor *topic_filter = &unsubscribe_view->topic_filters[i];
  1989. if (!aws_mqtt_is_valid_topic_filter_for_iot_core(*topic_filter)) {
  1990. AWS_LOGF_ERROR(
  1991. AWS_LS_MQTT5_GENERAL,
  1992. "id=%p: aws_mqtt5_packet_unsubscribe_view - topic filter not valid for AWS Iot Core limits: \"" PRInSTR
  1993. "\"",
  1994. (void *)unsubscribe_view,
  1995. AWS_BYTE_CURSOR_PRI(*topic_filter));
  1996. return aws_raise_error(AWS_ERROR_MQTT5_UNSUBSCRIBE_OPTIONS_VALIDATION);
  1997. }
  1998. }
  1999. return AWS_OP_SUCCESS;
  2000. }
  2001. void aws_mqtt5_packet_unsubscribe_view_log(
  2002. const struct aws_mqtt5_packet_unsubscribe_view *unsubscribe_view,
  2003. enum aws_log_level level) {
  2004. struct aws_logger *log_handle = aws_logger_get_conditional(AWS_LS_MQTT5_GENERAL, level);
  2005. if (log_handle == NULL) {
  2006. return;
  2007. }
  2008. size_t topic_count = unsubscribe_view->topic_filter_count;
  2009. for (size_t i = 0; i < topic_count; ++i) {
  2010. const struct aws_byte_cursor *topic_cursor = &unsubscribe_view->topic_filters[i];
  2011. AWS_LOGUF(
  2012. log_handle,
  2013. level,
  2014. AWS_LS_MQTT5_GENERAL,
  2015. "id=%p: aws_mqtt5_packet_unsubscribe_view topic #%zu: \"" PRInSTR "\"",
  2016. (void *)unsubscribe_view,
  2017. i,
  2018. AWS_BYTE_CURSOR_PRI(*topic_cursor));
  2019. }
  2020. s_aws_mqtt5_user_property_set_log(
  2021. log_handle,
  2022. unsubscribe_view->user_properties,
  2023. unsubscribe_view->user_property_count,
  2024. (void *)unsubscribe_view,
  2025. level,
  2026. "aws_mqtt5_packet_unsubscribe_view");
  2027. }
  2028. void aws_mqtt5_packet_unsubscribe_storage_clean_up(struct aws_mqtt5_packet_unsubscribe_storage *unsubscribe_storage) {
  2029. if (unsubscribe_storage == NULL) {
  2030. return;
  2031. }
  2032. aws_array_list_clean_up(&unsubscribe_storage->topic_filters);
  2033. aws_mqtt5_user_property_set_clean_up(&unsubscribe_storage->user_properties);
  2034. aws_byte_buf_clean_up(&unsubscribe_storage->storage);
  2035. }
  2036. static int s_aws_mqtt5_packet_unsubscribe_build_topic_list(
  2037. struct aws_mqtt5_packet_unsubscribe_storage *unsubscribe_storage,
  2038. struct aws_allocator *allocator,
  2039. size_t topic_count,
  2040. const struct aws_byte_cursor *topics) {
  2041. if (aws_array_list_init_dynamic(
  2042. &unsubscribe_storage->topic_filters, allocator, topic_count, sizeof(struct aws_byte_cursor))) {
  2043. return AWS_OP_ERR;
  2044. }
  2045. for (size_t i = 0; i < topic_count; ++i) {
  2046. const struct aws_byte_cursor *topic_cursor_ptr = &topics[i];
  2047. struct aws_byte_cursor topic_cursor = *topic_cursor_ptr;
  2048. if (aws_byte_buf_append_and_update(&unsubscribe_storage->storage, &topic_cursor)) {
  2049. return AWS_OP_ERR;
  2050. }
  2051. if (aws_array_list_push_back(&unsubscribe_storage->topic_filters, &topic_cursor)) {
  2052. return AWS_OP_ERR;
  2053. }
  2054. }
  2055. return AWS_OP_SUCCESS;
  2056. }
  2057. static size_t s_aws_mqtt5_packet_unsubscribe_compute_storage_size(
  2058. const struct aws_mqtt5_packet_unsubscribe_view *unsubscribe_view) {
  2059. size_t storage_size = s_aws_mqtt5_user_property_set_compute_storage_size(
  2060. unsubscribe_view->user_properties, unsubscribe_view->user_property_count);
  2061. for (size_t i = 0; i < unsubscribe_view->topic_filter_count; ++i) {
  2062. const struct aws_byte_cursor *topic = &unsubscribe_view->topic_filters[i];
  2063. storage_size += topic->len;
  2064. }
  2065. return storage_size;
  2066. }
  2067. int aws_mqtt5_packet_unsubscribe_storage_init(
  2068. struct aws_mqtt5_packet_unsubscribe_storage *unsubscribe_storage,
  2069. struct aws_allocator *allocator,
  2070. const struct aws_mqtt5_packet_unsubscribe_view *unsubscribe_options) {
  2071. AWS_ZERO_STRUCT(*unsubscribe_storage);
  2072. size_t storage_capacity = s_aws_mqtt5_packet_unsubscribe_compute_storage_size(unsubscribe_options);
  2073. if (aws_byte_buf_init(&unsubscribe_storage->storage, allocator, storage_capacity)) {
  2074. return AWS_OP_ERR;
  2075. }
  2076. struct aws_mqtt5_packet_unsubscribe_view *storage_view = &unsubscribe_storage->storage_view;
  2077. if (s_aws_mqtt5_packet_unsubscribe_build_topic_list(
  2078. unsubscribe_storage,
  2079. allocator,
  2080. unsubscribe_options->topic_filter_count,
  2081. unsubscribe_options->topic_filters)) {
  2082. return AWS_OP_ERR;
  2083. }
  2084. storage_view->topic_filter_count = aws_array_list_length(&unsubscribe_storage->topic_filters);
  2085. storage_view->topic_filters = unsubscribe_storage->topic_filters.data;
  2086. if (aws_mqtt5_user_property_set_init_with_storage(
  2087. &unsubscribe_storage->user_properties,
  2088. allocator,
  2089. &unsubscribe_storage->storage,
  2090. unsubscribe_options->user_property_count,
  2091. unsubscribe_options->user_properties)) {
  2092. return AWS_OP_ERR;
  2093. }
  2094. storage_view->user_property_count = aws_mqtt5_user_property_set_size(&unsubscribe_storage->user_properties);
  2095. storage_view->user_properties = unsubscribe_storage->user_properties.properties.data;
  2096. return AWS_OP_SUCCESS;
  2097. }
  2098. int aws_mqtt5_packet_unsubscribe_storage_init_from_external_storage(
  2099. struct aws_mqtt5_packet_unsubscribe_storage *unsubscribe_storage,
  2100. struct aws_allocator *allocator) {
  2101. AWS_ZERO_STRUCT(*unsubscribe_storage);
  2102. if (aws_mqtt5_user_property_set_init(&unsubscribe_storage->user_properties, allocator)) {
  2103. return AWS_OP_ERR;
  2104. }
  2105. if (aws_array_list_init_dynamic(
  2106. &unsubscribe_storage->topic_filters, allocator, 0, sizeof(struct aws_byte_cursor))) {
  2107. return AWS_OP_ERR;
  2108. }
  2109. return AWS_OP_SUCCESS;
  2110. }
  2111. static void s_aws_mqtt5_operation_unsubscribe_complete(
  2112. struct aws_mqtt5_operation *operation,
  2113. int error_code,
  2114. enum aws_mqtt5_packet_type packet_type,
  2115. const void *completion_view) {
  2116. struct aws_mqtt5_operation_unsubscribe *unsubscribe_op = operation->impl;
  2117. (void)packet_type;
  2118. if (unsubscribe_op->completion_options.completion_callback != NULL) {
  2119. (*unsubscribe_op->completion_options.completion_callback)(
  2120. completion_view, error_code, unsubscribe_op->completion_options.completion_user_data);
  2121. }
  2122. }
  2123. static void s_aws_mqtt5_operation_unsubscribe_set_packet_id(
  2124. struct aws_mqtt5_operation *operation,
  2125. aws_mqtt5_packet_id_t packet_id) {
  2126. struct aws_mqtt5_operation_unsubscribe *unsubscribe_op = operation->impl;
  2127. unsubscribe_op->options_storage.storage_view.packet_id = packet_id;
  2128. }
  2129. static aws_mqtt5_packet_id_t *s_aws_mqtt5_operation_unsubscribe_get_packet_id_address(
  2130. const struct aws_mqtt5_operation *operation) {
  2131. struct aws_mqtt5_operation_unsubscribe *unsubscribe_op = operation->impl;
  2132. return &unsubscribe_op->options_storage.storage_view.packet_id;
  2133. }
  2134. static struct aws_mqtt5_operation_vtable s_unsubscribe_operation_vtable = {
  2135. .aws_mqtt5_operation_completion_fn = s_aws_mqtt5_operation_unsubscribe_complete,
  2136. .aws_mqtt5_operation_set_packet_id_fn = s_aws_mqtt5_operation_unsubscribe_set_packet_id,
  2137. .aws_mqtt5_operation_get_packet_id_address_fn = s_aws_mqtt5_operation_unsubscribe_get_packet_id_address,
  2138. .aws_mqtt5_operation_validate_vs_connection_settings_fn = NULL,
  2139. };
  2140. static void s_destroy_operation_unsubscribe(void *object) {
  2141. if (object == NULL) {
  2142. return;
  2143. }
  2144. struct aws_mqtt5_operation_unsubscribe *unsubscribe_op = object;
  2145. aws_mqtt5_packet_unsubscribe_storage_clean_up(&unsubscribe_op->options_storage);
  2146. aws_mem_release(unsubscribe_op->allocator, unsubscribe_op);
  2147. }
  2148. struct aws_mqtt5_operation_unsubscribe *aws_mqtt5_operation_unsubscribe_new(
  2149. struct aws_allocator *allocator,
  2150. const struct aws_mqtt5_client *client,
  2151. const struct aws_mqtt5_packet_unsubscribe_view *unsubscribe_options,
  2152. const struct aws_mqtt5_unsubscribe_completion_options *completion_options) {
  2153. AWS_PRECONDITION(allocator != NULL);
  2154. AWS_PRECONDITION(unsubscribe_options != NULL);
  2155. if (aws_mqtt5_packet_unsubscribe_view_validate(unsubscribe_options)) {
  2156. return NULL;
  2157. }
  2158. if (unsubscribe_options->packet_id != 0) {
  2159. AWS_LOGF_DEBUG(
  2160. AWS_LS_MQTT5_GENERAL,
  2161. "id=%p: aws_mqtt5_packet_unsubscribe_view packet id must be zero",
  2162. (void *)unsubscribe_options);
  2163. aws_raise_error(AWS_ERROR_MQTT5_UNSUBSCRIBE_OPTIONS_VALIDATION);
  2164. return NULL;
  2165. }
  2166. if (client != NULL && client->config->extended_validation_and_flow_control_options != AWS_MQTT5_EVAFCO_NONE) {
  2167. if (aws_mqtt5_packet_unsubscribe_view_validate_vs_iot_core(unsubscribe_options)) {
  2168. return NULL;
  2169. }
  2170. }
  2171. struct aws_mqtt5_operation_unsubscribe *unsubscribe_op =
  2172. aws_mem_calloc(allocator, 1, sizeof(struct aws_mqtt5_operation_unsubscribe));
  2173. if (unsubscribe_op == NULL) {
  2174. return NULL;
  2175. }
  2176. unsubscribe_op->allocator = allocator;
  2177. unsubscribe_op->base.vtable = &s_unsubscribe_operation_vtable;
  2178. unsubscribe_op->base.packet_type = AWS_MQTT5_PT_UNSUBSCRIBE;
  2179. aws_ref_count_init(&unsubscribe_op->base.ref_count, unsubscribe_op, s_destroy_operation_unsubscribe);
  2180. unsubscribe_op->base.impl = unsubscribe_op;
  2181. if (aws_mqtt5_packet_unsubscribe_storage_init(&unsubscribe_op->options_storage, allocator, unsubscribe_options)) {
  2182. goto error;
  2183. }
  2184. unsubscribe_op->base.packet_view = &unsubscribe_op->options_storage.storage_view;
  2185. if (completion_options != NULL) {
  2186. unsubscribe_op->completion_options = *completion_options;
  2187. }
  2188. return unsubscribe_op;
  2189. error:
  2190. aws_mqtt5_operation_release(&unsubscribe_op->base);
  2191. return NULL;
  2192. }
  2193. /*********************************************************************************************************************
  2194. * Subscribe
  2195. ********************************************************************************************************************/
  2196. static int s_aws_mqtt5_validate_subscription(
  2197. const struct aws_mqtt5_subscription_view *subscription,
  2198. void *log_context) {
  2199. if (aws_mqtt5_validate_utf8_text(subscription->topic_filter)) {
  2200. AWS_LOGF_ERROR(
  2201. AWS_LS_MQTT5_GENERAL,
  2202. "id=%p: aws_mqtt5_packet_subscribe_view - topic filter \"" PRInSTR "\" not valid UTF-8 in subscription",
  2203. log_context,
  2204. AWS_BYTE_CURSOR_PRI(subscription->topic_filter));
  2205. return aws_raise_error(AWS_ERROR_MQTT5_SUBSCRIBE_OPTIONS_VALIDATION);
  2206. }
  2207. if (!aws_mqtt_is_valid_topic_filter(&subscription->topic_filter)) {
  2208. AWS_LOGF_ERROR(
  2209. AWS_LS_MQTT5_GENERAL,
  2210. "id=%p: aws_mqtt5_packet_subscribe_view - invalid topic filter \"" PRInSTR "\" in subscription",
  2211. log_context,
  2212. AWS_BYTE_CURSOR_PRI(subscription->topic_filter));
  2213. return aws_raise_error(AWS_ERROR_MQTT5_SUBSCRIBE_OPTIONS_VALIDATION);
  2214. }
  2215. if (subscription->topic_filter.len > UINT16_MAX) {
  2216. AWS_LOGF_ERROR(
  2217. AWS_LS_MQTT5_GENERAL,
  2218. "id=%p: aws_mqtt5_packet_subscribe_view - subscription contains too-long topic filter",
  2219. log_context);
  2220. return aws_raise_error(AWS_ERROR_MQTT5_SUBSCRIBE_OPTIONS_VALIDATION);
  2221. }
  2222. if (subscription->qos < AWS_MQTT5_QOS_AT_MOST_ONCE || subscription->qos > AWS_MQTT5_QOS_AT_LEAST_ONCE) {
  2223. AWS_LOGF_ERROR(
  2224. AWS_LS_MQTT5_GENERAL,
  2225. "id=%p: aws_mqtt5_packet_subscribe_view - unsupported QoS value: %d",
  2226. log_context,
  2227. (int)subscription->qos);
  2228. return aws_raise_error(AWS_ERROR_MQTT5_SUBSCRIBE_OPTIONS_VALIDATION);
  2229. }
  2230. if (subscription->retain_handling_type < AWS_MQTT5_RHT_SEND_ON_SUBSCRIBE ||
  2231. subscription->retain_handling_type > AWS_MQTT5_RHT_DONT_SEND) {
  2232. AWS_LOGF_ERROR(
  2233. AWS_LS_MQTT5_GENERAL,
  2234. "id=%p: aws_mqtt5_packet_subscribe_view - unsupported retain handling value: %d",
  2235. log_context,
  2236. (int)subscription->retain_handling_type);
  2237. return aws_raise_error(AWS_ERROR_MQTT5_SUBSCRIBE_OPTIONS_VALIDATION);
  2238. }
  2239. /* mqtt5 forbids no_local to be set to 1 if the topic filter represents a shared subscription */
  2240. if (subscription->no_local) {
  2241. if (aws_mqtt_is_topic_filter_shared_subscription(subscription->topic_filter)) {
  2242. AWS_LOGF_ERROR(
  2243. AWS_LS_MQTT5_GENERAL,
  2244. "id=%p: aws_mqtt5_packet_subscribe_view - no_local cannot be 1 if the topic filter is a shared"
  2245. "subscription",
  2246. log_context);
  2247. return aws_raise_error(AWS_ERROR_MQTT5_SUBSCRIBE_OPTIONS_VALIDATION);
  2248. }
  2249. }
  2250. return AWS_OP_SUCCESS;
  2251. }
  2252. int aws_mqtt5_packet_subscribe_view_validate(const struct aws_mqtt5_packet_subscribe_view *subscribe_view) {
  2253. if (subscribe_view == NULL) {
  2254. AWS_LOGF_ERROR(AWS_LS_MQTT5_GENERAL, "null SUBSCRIBE packet options");
  2255. return aws_raise_error(AWS_ERROR_INVALID_ARGUMENT);
  2256. }
  2257. if (subscribe_view->subscription_count == 0) {
  2258. AWS_LOGF_ERROR(
  2259. AWS_LS_MQTT5_GENERAL,
  2260. "id=%p: aws_mqtt5_packet_subscribe_view - must contain at least one subscription",
  2261. (void *)subscribe_view);
  2262. return aws_raise_error(AWS_ERROR_MQTT5_SUBSCRIBE_OPTIONS_VALIDATION);
  2263. }
  2264. if (subscribe_view->subscription_count > AWS_MQTT5_CLIENT_MAXIMUM_SUBSCRIPTIONS_PER_SUBSCRIBE) {
  2265. AWS_LOGF_ERROR(
  2266. AWS_LS_MQTT5_GENERAL,
  2267. "id=%p: aws_mqtt5_packet_subscribe_view - too many subscriptions",
  2268. (void *)subscribe_view);
  2269. return aws_raise_error(AWS_ERROR_MQTT5_SUBSCRIBE_OPTIONS_VALIDATION);
  2270. }
  2271. for (size_t i = 0; i < subscribe_view->subscription_count; ++i) {
  2272. const struct aws_mqtt5_subscription_view *subscription = &subscribe_view->subscriptions[i];
  2273. if (s_aws_mqtt5_validate_subscription(subscription, (void *)subscribe_view)) {
  2274. AWS_LOGF_ERROR(
  2275. AWS_LS_MQTT5_GENERAL,
  2276. "id=%p: aws_mqtt5_packet_subscribe_view - invalid subscription",
  2277. (void *)subscribe_view);
  2278. return aws_raise_error(AWS_ERROR_MQTT5_SUBSCRIBE_OPTIONS_VALIDATION);
  2279. }
  2280. }
  2281. if (subscribe_view->subscription_identifier != NULL) {
  2282. if (*subscribe_view->subscription_identifier > AWS_MQTT5_MAXIMUM_VARIABLE_LENGTH_INTEGER) {
  2283. AWS_LOGF_ERROR(
  2284. AWS_LS_MQTT5_GENERAL,
  2285. "id=%p: aws_mqtt5_packet_subscribe_view - subscription identifier (%" PRIu32 ") too large",
  2286. (void *)subscribe_view,
  2287. *subscribe_view->subscription_identifier);
  2288. return aws_raise_error(AWS_ERROR_MQTT5_SUBSCRIBE_OPTIONS_VALIDATION);
  2289. }
  2290. }
  2291. if (s_aws_mqtt5_user_property_set_validate(
  2292. subscribe_view->user_properties,
  2293. subscribe_view->user_property_count,
  2294. "aws_mqtt5_packet_subscribe_view",
  2295. (void *)subscribe_view)) {
  2296. return AWS_OP_ERR;
  2297. }
  2298. return AWS_OP_SUCCESS;
  2299. }
  2300. AWS_MQTT_API int aws_mqtt5_packet_subscribe_view_validate_vs_iot_core(
  2301. const struct aws_mqtt5_packet_subscribe_view *subscribe_view) {
  2302. if (subscribe_view->subscription_count > AWS_IOT_CORE_MAXIMUM_SUSBCRIPTIONS_PER_SUBSCRIBE) {
  2303. AWS_LOGF_ERROR(
  2304. AWS_LS_MQTT5_GENERAL,
  2305. "id=%p: aws_mqtt5_packet_subscribe_view - number of subscriptions (%zu) exceeds default AWS IoT Core limit "
  2306. "(%d)",
  2307. (void *)subscribe_view,
  2308. subscribe_view->subscription_count,
  2309. (int)AWS_IOT_CORE_MAXIMUM_SUSBCRIPTIONS_PER_SUBSCRIBE);
  2310. return AWS_OP_ERR;
  2311. }
  2312. for (size_t i = 0; i < subscribe_view->subscription_count; ++i) {
  2313. const struct aws_mqtt5_subscription_view *subscription = &subscribe_view->subscriptions[i];
  2314. const struct aws_byte_cursor *topic_filter = &subscription->topic_filter;
  2315. if (!aws_mqtt_is_valid_topic_filter_for_iot_core(*topic_filter)) {
  2316. AWS_LOGF_ERROR(
  2317. AWS_LS_MQTT5_GENERAL,
  2318. "id=%p: aws_mqtt5_packet_subscribe_view - topic filter not valid for AWS Iot Core limits: \"" PRInSTR
  2319. "\"",
  2320. (void *)subscribe_view,
  2321. AWS_BYTE_CURSOR_PRI(*topic_filter));
  2322. return aws_raise_error(AWS_ERROR_MQTT5_UNSUBSCRIBE_OPTIONS_VALIDATION);
  2323. }
  2324. }
  2325. return AWS_OP_SUCCESS;
  2326. }
  2327. void aws_mqtt5_packet_subscribe_view_log(
  2328. const struct aws_mqtt5_packet_subscribe_view *subscribe_view,
  2329. enum aws_log_level level) {
  2330. struct aws_logger *log_handle = aws_logger_get_conditional(AWS_LS_MQTT5_GENERAL, level);
  2331. if (log_handle == NULL) {
  2332. return;
  2333. }
  2334. size_t subscription_count = subscribe_view->subscription_count;
  2335. for (size_t i = 0; i < subscription_count; ++i) {
  2336. const struct aws_mqtt5_subscription_view *view = &subscribe_view->subscriptions[i];
  2337. AWS_LOGUF(
  2338. log_handle,
  2339. level,
  2340. AWS_LS_MQTT5_GENERAL,
  2341. "id=%p: aws_mqtt5_packet_subscribe_view subscription #%zu, topic filter \"" PRInSTR
  2342. "\", qos %d, no local %d, retain as "
  2343. "published %d, retain handling %d (%s)",
  2344. (void *)subscribe_view,
  2345. i,
  2346. AWS_BYTE_CURSOR_PRI(view->topic_filter),
  2347. (int)view->qos,
  2348. (int)view->no_local,
  2349. (int)view->retain_as_published,
  2350. (int)view->retain_handling_type,
  2351. aws_mqtt5_retain_handling_type_to_c_string(view->retain_handling_type));
  2352. }
  2353. if (subscribe_view->subscription_identifier != NULL) {
  2354. AWS_LOGUF(
  2355. log_handle,
  2356. level,
  2357. AWS_LS_MQTT5_GENERAL,
  2358. "id=%p: aws_mqtt5_packet_subscribe_view subscription identifier set to %" PRIu32,
  2359. (void *)subscribe_view,
  2360. *subscribe_view->subscription_identifier);
  2361. }
  2362. s_aws_mqtt5_user_property_set_log(
  2363. log_handle,
  2364. subscribe_view->user_properties,
  2365. subscribe_view->user_property_count,
  2366. (void *)subscribe_view,
  2367. level,
  2368. "aws_mqtt5_packet_subscribe_view");
  2369. }
  2370. void aws_mqtt5_packet_subscribe_storage_clean_up(struct aws_mqtt5_packet_subscribe_storage *subscribe_storage) {
  2371. if (subscribe_storage == NULL) {
  2372. return;
  2373. }
  2374. aws_array_list_clean_up(&subscribe_storage->subscriptions);
  2375. aws_mqtt5_user_property_set_clean_up(&subscribe_storage->user_properties);
  2376. aws_byte_buf_clean_up(&subscribe_storage->storage);
  2377. }
  2378. static int s_aws_mqtt5_packet_subscribe_storage_init_subscriptions(
  2379. struct aws_mqtt5_packet_subscribe_storage *subscribe_storage,
  2380. struct aws_allocator *allocator,
  2381. size_t subscription_count,
  2382. const struct aws_mqtt5_subscription_view *subscriptions) {
  2383. if (aws_array_list_init_dynamic(
  2384. &subscribe_storage->subscriptions,
  2385. allocator,
  2386. subscription_count,
  2387. sizeof(struct aws_mqtt5_subscription_view))) {
  2388. return AWS_OP_ERR;
  2389. }
  2390. for (size_t i = 0; i < subscription_count; ++i) {
  2391. const struct aws_mqtt5_subscription_view *source = &subscriptions[i];
  2392. struct aws_mqtt5_subscription_view copy = *source;
  2393. if (aws_byte_buf_append_and_update(&subscribe_storage->storage, &copy.topic_filter)) {
  2394. return AWS_OP_ERR;
  2395. }
  2396. if (aws_array_list_push_back(&subscribe_storage->subscriptions, &copy)) {
  2397. return AWS_OP_ERR;
  2398. }
  2399. }
  2400. return AWS_OP_SUCCESS;
  2401. }
  2402. static size_t s_aws_mqtt5_packet_subscribe_compute_storage_size(
  2403. const struct aws_mqtt5_packet_subscribe_view *subscribe_view) {
  2404. size_t storage_size = s_aws_mqtt5_user_property_set_compute_storage_size(
  2405. subscribe_view->user_properties, subscribe_view->user_property_count);
  2406. for (size_t i = 0; i < subscribe_view->subscription_count; ++i) {
  2407. const struct aws_mqtt5_subscription_view *subscription = &subscribe_view->subscriptions[i];
  2408. storage_size += subscription->topic_filter.len;
  2409. }
  2410. return storage_size;
  2411. }
  2412. int aws_mqtt5_packet_subscribe_storage_init(
  2413. struct aws_mqtt5_packet_subscribe_storage *subscribe_storage,
  2414. struct aws_allocator *allocator,
  2415. const struct aws_mqtt5_packet_subscribe_view *subscribe_options) {
  2416. AWS_ZERO_STRUCT(*subscribe_storage);
  2417. size_t storage_capacity = s_aws_mqtt5_packet_subscribe_compute_storage_size(subscribe_options);
  2418. if (aws_byte_buf_init(&subscribe_storage->storage, allocator, storage_capacity)) {
  2419. return AWS_OP_ERR;
  2420. }
  2421. struct aws_mqtt5_packet_subscribe_view *storage_view = &subscribe_storage->storage_view;
  2422. storage_view->packet_id = subscribe_options->packet_id;
  2423. if (subscribe_options->subscription_identifier != NULL) {
  2424. subscribe_storage->subscription_identifier = *subscribe_options->subscription_identifier;
  2425. storage_view->subscription_identifier = &subscribe_storage->subscription_identifier;
  2426. }
  2427. if (s_aws_mqtt5_packet_subscribe_storage_init_subscriptions(
  2428. subscribe_storage, allocator, subscribe_options->subscription_count, subscribe_options->subscriptions)) {
  2429. return AWS_OP_ERR;
  2430. }
  2431. storage_view->subscription_count = aws_array_list_length(&subscribe_storage->subscriptions);
  2432. storage_view->subscriptions = subscribe_storage->subscriptions.data;
  2433. if (aws_mqtt5_user_property_set_init_with_storage(
  2434. &subscribe_storage->user_properties,
  2435. allocator,
  2436. &subscribe_storage->storage,
  2437. subscribe_options->user_property_count,
  2438. subscribe_options->user_properties)) {
  2439. return AWS_OP_ERR;
  2440. }
  2441. storage_view->user_property_count = aws_mqtt5_user_property_set_size(&subscribe_storage->user_properties);
  2442. storage_view->user_properties = subscribe_storage->user_properties.properties.data;
  2443. return AWS_OP_SUCCESS;
  2444. }
  2445. int aws_mqtt5_packet_subscribe_storage_init_from_external_storage(
  2446. struct aws_mqtt5_packet_subscribe_storage *subscribe_storage,
  2447. struct aws_allocator *allocator) {
  2448. AWS_ZERO_STRUCT(*subscribe_storage);
  2449. if (aws_mqtt5_user_property_set_init(&subscribe_storage->user_properties, allocator)) {
  2450. return AWS_OP_ERR;
  2451. }
  2452. if (aws_array_list_init_dynamic(
  2453. &subscribe_storage->subscriptions, allocator, 0, sizeof(struct aws_mqtt5_subscription_view))) {
  2454. return AWS_OP_ERR;
  2455. }
  2456. return AWS_OP_SUCCESS;
  2457. }
  2458. static void s_aws_mqtt5_operation_subscribe_complete(
  2459. struct aws_mqtt5_operation *operation,
  2460. int error_code,
  2461. enum aws_mqtt5_packet_type packet_type,
  2462. const void *completion_view) {
  2463. (void)packet_type;
  2464. struct aws_mqtt5_operation_subscribe *subscribe_op = operation->impl;
  2465. if (subscribe_op->completion_options.completion_callback != NULL) {
  2466. (*subscribe_op->completion_options.completion_callback)(
  2467. completion_view, error_code, subscribe_op->completion_options.completion_user_data);
  2468. }
  2469. }
  2470. static void s_aws_mqtt5_operation_subscribe_set_packet_id(
  2471. struct aws_mqtt5_operation *operation,
  2472. aws_mqtt5_packet_id_t packet_id) {
  2473. struct aws_mqtt5_operation_subscribe *subscribe_op = operation->impl;
  2474. subscribe_op->options_storage.storage_view.packet_id = packet_id;
  2475. }
  2476. static aws_mqtt5_packet_id_t *s_aws_mqtt5_operation_subscribe_get_packet_id_address(
  2477. const struct aws_mqtt5_operation *operation) {
  2478. struct aws_mqtt5_operation_subscribe *subscribe_op = operation->impl;
  2479. return &subscribe_op->options_storage.storage_view.packet_id;
  2480. }
  2481. static struct aws_mqtt5_operation_vtable s_subscribe_operation_vtable = {
  2482. .aws_mqtt5_operation_completion_fn = s_aws_mqtt5_operation_subscribe_complete,
  2483. .aws_mqtt5_operation_set_packet_id_fn = s_aws_mqtt5_operation_subscribe_set_packet_id,
  2484. .aws_mqtt5_operation_get_packet_id_address_fn = s_aws_mqtt5_operation_subscribe_get_packet_id_address,
  2485. .aws_mqtt5_operation_validate_vs_connection_settings_fn = NULL,
  2486. };
  2487. static void s_destroy_operation_subscribe(void *object) {
  2488. if (object == NULL) {
  2489. return;
  2490. }
  2491. struct aws_mqtt5_operation_subscribe *subscribe_op = object;
  2492. aws_mqtt5_packet_subscribe_storage_clean_up(&subscribe_op->options_storage);
  2493. aws_mem_release(subscribe_op->allocator, subscribe_op);
  2494. }
  2495. struct aws_mqtt5_operation_subscribe *aws_mqtt5_operation_subscribe_new(
  2496. struct aws_allocator *allocator,
  2497. const struct aws_mqtt5_client *client,
  2498. const struct aws_mqtt5_packet_subscribe_view *subscribe_options,
  2499. const struct aws_mqtt5_subscribe_completion_options *completion_options) {
  2500. AWS_PRECONDITION(allocator != NULL);
  2501. AWS_PRECONDITION(subscribe_options != NULL);
  2502. if (aws_mqtt5_packet_subscribe_view_validate(subscribe_options)) {
  2503. return NULL;
  2504. }
  2505. if (subscribe_options->packet_id != 0) {
  2506. AWS_LOGF_DEBUG(
  2507. AWS_LS_MQTT5_GENERAL,
  2508. "id=%p: aws_mqtt5_packet_subscribe_view packet id must be zero",
  2509. (void *)subscribe_options);
  2510. aws_raise_error(AWS_ERROR_MQTT5_SUBSCRIBE_OPTIONS_VALIDATION);
  2511. return NULL;
  2512. }
  2513. if (client != NULL && client->config->extended_validation_and_flow_control_options != AWS_MQTT5_EVAFCO_NONE) {
  2514. if (aws_mqtt5_packet_subscribe_view_validate_vs_iot_core(subscribe_options)) {
  2515. return NULL;
  2516. }
  2517. }
  2518. struct aws_mqtt5_operation_subscribe *subscribe_op =
  2519. aws_mem_calloc(allocator, 1, sizeof(struct aws_mqtt5_operation_subscribe));
  2520. if (subscribe_op == NULL) {
  2521. return NULL;
  2522. }
  2523. subscribe_op->allocator = allocator;
  2524. subscribe_op->base.vtable = &s_subscribe_operation_vtable;
  2525. subscribe_op->base.packet_type = AWS_MQTT5_PT_SUBSCRIBE;
  2526. aws_ref_count_init(&subscribe_op->base.ref_count, subscribe_op, s_destroy_operation_subscribe);
  2527. subscribe_op->base.impl = subscribe_op;
  2528. if (aws_mqtt5_packet_subscribe_storage_init(&subscribe_op->options_storage, allocator, subscribe_options)) {
  2529. goto error;
  2530. }
  2531. subscribe_op->base.packet_view = &subscribe_op->options_storage.storage_view;
  2532. if (completion_options != NULL) {
  2533. subscribe_op->completion_options = *completion_options;
  2534. }
  2535. return subscribe_op;
  2536. error:
  2537. aws_mqtt5_operation_release(&subscribe_op->base);
  2538. return NULL;
  2539. }
  2540. /*********************************************************************************************************************
  2541. * Suback
  2542. ********************************************************************************************************************/
  2543. static size_t s_aws_mqtt5_packet_suback_compute_storage_size(const struct aws_mqtt5_packet_suback_view *suback_view) {
  2544. size_t storage_size = s_aws_mqtt5_user_property_set_compute_storage_size(
  2545. suback_view->user_properties, suback_view->user_property_count);
  2546. if (suback_view->reason_string != NULL) {
  2547. storage_size += suback_view->reason_string->len;
  2548. }
  2549. return storage_size;
  2550. }
  2551. static int s_aws_mqtt5_packet_suback_storage_init_reason_codes(
  2552. struct aws_mqtt5_packet_suback_storage *suback_storage,
  2553. struct aws_allocator *allocator,
  2554. size_t reason_code_count,
  2555. const enum aws_mqtt5_suback_reason_code *reason_codes) {
  2556. if (aws_array_list_init_dynamic(
  2557. &suback_storage->reason_codes, allocator, reason_code_count, sizeof(enum aws_mqtt5_suback_reason_code))) {
  2558. return AWS_OP_ERR;
  2559. }
  2560. for (size_t i = 0; i < reason_code_count; ++i) {
  2561. aws_array_list_push_back(&suback_storage->reason_codes, &reason_codes[i]);
  2562. }
  2563. return AWS_OP_SUCCESS;
  2564. }
  2565. AWS_MQTT_API int aws_mqtt5_packet_suback_storage_init(
  2566. struct aws_mqtt5_packet_suback_storage *suback_storage,
  2567. struct aws_allocator *allocator,
  2568. const struct aws_mqtt5_packet_suback_view *suback_view) {
  2569. AWS_ZERO_STRUCT(*suback_storage);
  2570. size_t storage_capacity = s_aws_mqtt5_packet_suback_compute_storage_size(suback_view);
  2571. if (aws_byte_buf_init(&suback_storage->storage, allocator, storage_capacity)) {
  2572. return AWS_OP_ERR;
  2573. }
  2574. struct aws_mqtt5_packet_suback_view *storage_view = &suback_storage->storage_view;
  2575. storage_view->packet_id = suback_view->packet_id;
  2576. if (suback_view->reason_string != NULL) {
  2577. suback_storage->reason_string = *suback_view->reason_string;
  2578. if (aws_byte_buf_append_and_update(&suback_storage->storage, &suback_storage->reason_string)) {
  2579. return AWS_OP_ERR;
  2580. }
  2581. storage_view->reason_string = &suback_storage->reason_string;
  2582. }
  2583. if (s_aws_mqtt5_packet_suback_storage_init_reason_codes(
  2584. suback_storage, allocator, suback_view->reason_code_count, suback_view->reason_codes)) {
  2585. return AWS_OP_ERR;
  2586. }
  2587. storage_view->reason_code_count = aws_array_list_length(&suback_storage->reason_codes);
  2588. storage_view->reason_codes = suback_storage->reason_codes.data;
  2589. if (aws_mqtt5_user_property_set_init_with_storage(
  2590. &suback_storage->user_properties,
  2591. allocator,
  2592. &suback_storage->storage,
  2593. suback_view->user_property_count,
  2594. suback_view->user_properties)) {
  2595. return AWS_OP_ERR;
  2596. }
  2597. storage_view->user_property_count = aws_mqtt5_user_property_set_size(&suback_storage->user_properties);
  2598. storage_view->user_properties = suback_storage->user_properties.properties.data;
  2599. return AWS_OP_SUCCESS;
  2600. }
  2601. int aws_mqtt5_packet_suback_storage_init_from_external_storage(
  2602. struct aws_mqtt5_packet_suback_storage *suback_storage,
  2603. struct aws_allocator *allocator) {
  2604. AWS_ZERO_STRUCT(*suback_storage);
  2605. if (aws_mqtt5_user_property_set_init(&suback_storage->user_properties, allocator)) {
  2606. return AWS_OP_ERR;
  2607. }
  2608. if (aws_array_list_init_dynamic(
  2609. &suback_storage->reason_codes, allocator, 0, sizeof(enum aws_mqtt5_suback_reason_code))) {
  2610. return AWS_OP_ERR;
  2611. }
  2612. return AWS_OP_SUCCESS;
  2613. }
  2614. void aws_mqtt5_packet_suback_storage_clean_up(struct aws_mqtt5_packet_suback_storage *suback_storage) {
  2615. if (suback_storage == NULL) {
  2616. return;
  2617. }
  2618. aws_mqtt5_user_property_set_clean_up(&suback_storage->user_properties);
  2619. aws_array_list_clean_up(&suback_storage->reason_codes);
  2620. aws_byte_buf_clean_up(&suback_storage->storage);
  2621. }
  2622. void aws_mqtt5_packet_suback_view_log(
  2623. const struct aws_mqtt5_packet_suback_view *suback_view,
  2624. enum aws_log_level level) {
  2625. struct aws_logger *log_handle = aws_logger_get_conditional(AWS_LS_MQTT5_GENERAL, level);
  2626. if (log_handle == NULL) {
  2627. return;
  2628. }
  2629. AWS_LOGUF(
  2630. log_handle,
  2631. level,
  2632. AWS_LS_MQTT5_GENERAL,
  2633. "id=%p: aws_mqtt5_packet_suback_view packet id set to %d",
  2634. (void *)suback_view,
  2635. (int)suback_view->packet_id);
  2636. for (size_t i = 0; i < suback_view->reason_code_count; ++i) {
  2637. enum aws_mqtt5_suback_reason_code reason_code = suback_view->reason_codes[i];
  2638. AWS_LOGUF(
  2639. log_handle,
  2640. level,
  2641. AWS_LS_MQTT5_GENERAL,
  2642. "id=%p: aws_mqtt5_packet_suback_view topic #%zu, reason code %d (%s)",
  2643. (void *)suback_view,
  2644. i,
  2645. (int)reason_code,
  2646. aws_mqtt5_suback_reason_code_to_c_string(reason_code));
  2647. }
  2648. s_aws_mqtt5_user_property_set_log(
  2649. log_handle,
  2650. suback_view->user_properties,
  2651. suback_view->user_property_count,
  2652. (void *)suback_view,
  2653. level,
  2654. "aws_mqtt5_packet_suback_view");
  2655. }
  2656. /*********************************************************************************************************************
  2657. * Unsuback
  2658. ********************************************************************************************************************/
  2659. static size_t s_aws_mqtt5_packet_unsuback_compute_storage_size(
  2660. const struct aws_mqtt5_packet_unsuback_view *unsuback_view) {
  2661. size_t storage_size = s_aws_mqtt5_user_property_set_compute_storage_size(
  2662. unsuback_view->user_properties, unsuback_view->user_property_count);
  2663. if (unsuback_view->reason_string != NULL) {
  2664. storage_size += unsuback_view->reason_string->len;
  2665. }
  2666. return storage_size;
  2667. }
  2668. static int s_aws_mqtt5_packet_unsuback_storage_init_reason_codes(
  2669. struct aws_mqtt5_packet_unsuback_storage *unsuback_storage,
  2670. struct aws_allocator *allocator,
  2671. size_t reason_code_count,
  2672. const enum aws_mqtt5_unsuback_reason_code *reason_codes) {
  2673. if (aws_array_list_init_dynamic(
  2674. &unsuback_storage->reason_codes,
  2675. allocator,
  2676. reason_code_count,
  2677. sizeof(enum aws_mqtt5_unsuback_reason_code))) {
  2678. return AWS_OP_ERR;
  2679. }
  2680. for (size_t i = 0; i < reason_code_count; ++i) {
  2681. aws_array_list_push_back(&unsuback_storage->reason_codes, &reason_codes[i]);
  2682. }
  2683. return AWS_OP_SUCCESS;
  2684. }
  2685. AWS_MQTT_API int aws_mqtt5_packet_unsuback_storage_init(
  2686. struct aws_mqtt5_packet_unsuback_storage *unsuback_storage,
  2687. struct aws_allocator *allocator,
  2688. const struct aws_mqtt5_packet_unsuback_view *unsuback_view) {
  2689. AWS_ZERO_STRUCT(*unsuback_storage);
  2690. size_t storage_capacity = s_aws_mqtt5_packet_unsuback_compute_storage_size(unsuback_view);
  2691. if (aws_byte_buf_init(&unsuback_storage->storage, allocator, storage_capacity)) {
  2692. return AWS_OP_ERR;
  2693. }
  2694. struct aws_mqtt5_packet_unsuback_view *storage_view = &unsuback_storage->storage_view;
  2695. storage_view->packet_id = unsuback_view->packet_id;
  2696. if (unsuback_view->reason_string != NULL) {
  2697. unsuback_storage->reason_string = *unsuback_view->reason_string;
  2698. if (aws_byte_buf_append_and_update(&unsuback_storage->storage, &unsuback_storage->reason_string)) {
  2699. return AWS_OP_ERR;
  2700. }
  2701. storage_view->reason_string = &unsuback_storage->reason_string;
  2702. }
  2703. if (s_aws_mqtt5_packet_unsuback_storage_init_reason_codes(
  2704. unsuback_storage, allocator, unsuback_view->reason_code_count, unsuback_view->reason_codes)) {
  2705. return AWS_OP_ERR;
  2706. }
  2707. storage_view->reason_code_count = aws_array_list_length(&unsuback_storage->reason_codes);
  2708. storage_view->reason_codes = unsuback_storage->reason_codes.data;
  2709. if (aws_mqtt5_user_property_set_init_with_storage(
  2710. &unsuback_storage->user_properties,
  2711. allocator,
  2712. &unsuback_storage->storage,
  2713. unsuback_view->user_property_count,
  2714. unsuback_view->user_properties)) {
  2715. return AWS_OP_ERR;
  2716. }
  2717. storage_view->user_property_count = aws_mqtt5_user_property_set_size(&unsuback_storage->user_properties);
  2718. storage_view->user_properties = unsuback_storage->user_properties.properties.data;
  2719. return AWS_OP_SUCCESS;
  2720. }
  2721. int aws_mqtt5_packet_unsuback_storage_init_from_external_storage(
  2722. struct aws_mqtt5_packet_unsuback_storage *unsuback_storage,
  2723. struct aws_allocator *allocator) {
  2724. AWS_ZERO_STRUCT(*unsuback_storage);
  2725. if (aws_mqtt5_user_property_set_init(&unsuback_storage->user_properties, allocator)) {
  2726. return AWS_OP_ERR;
  2727. }
  2728. if (aws_array_list_init_dynamic(
  2729. &unsuback_storage->reason_codes, allocator, 0, sizeof(enum aws_mqtt5_unsuback_reason_code))) {
  2730. return AWS_OP_ERR;
  2731. }
  2732. return AWS_OP_SUCCESS;
  2733. }
  2734. void aws_mqtt5_packet_unsuback_storage_clean_up(struct aws_mqtt5_packet_unsuback_storage *unsuback_storage) {
  2735. if (unsuback_storage == NULL) {
  2736. return;
  2737. }
  2738. aws_mqtt5_user_property_set_clean_up(&unsuback_storage->user_properties);
  2739. aws_array_list_clean_up(&unsuback_storage->reason_codes);
  2740. aws_byte_buf_clean_up(&unsuback_storage->storage);
  2741. }
  2742. void aws_mqtt5_packet_unsuback_view_log(
  2743. const struct aws_mqtt5_packet_unsuback_view *unsuback_view,
  2744. enum aws_log_level level) {
  2745. struct aws_logger *log_handle = aws_logger_get_conditional(AWS_LS_MQTT5_GENERAL, level);
  2746. if (log_handle == NULL) {
  2747. return;
  2748. }
  2749. AWS_LOGUF(
  2750. log_handle,
  2751. level,
  2752. AWS_LS_MQTT5_GENERAL,
  2753. "id=%p: aws_mqtt5_packet_unsuback_view packet id set to %d",
  2754. (void *)unsuback_view,
  2755. (int)unsuback_view->packet_id);
  2756. for (size_t i = 0; i < unsuback_view->reason_code_count; ++i) {
  2757. enum aws_mqtt5_unsuback_reason_code reason_code = unsuback_view->reason_codes[i];
  2758. AWS_LOGUF(
  2759. log_handle,
  2760. level,
  2761. AWS_LS_MQTT5_GENERAL,
  2762. "id=%p: aws_mqtt5_packet_unsuback_view topic #%zu, reason code %d (%s)",
  2763. (void *)unsuback_view,
  2764. i,
  2765. (int)reason_code,
  2766. aws_mqtt5_unsuback_reason_code_to_c_string(reason_code));
  2767. }
  2768. s_aws_mqtt5_user_property_set_log(
  2769. log_handle,
  2770. unsuback_view->user_properties,
  2771. unsuback_view->user_property_count,
  2772. (void *)unsuback_view,
  2773. level,
  2774. "aws_mqtt5_packet_unsuback_view");
  2775. }
  2776. /*********************************************************************************************************************
  2777. * PINGREQ
  2778. ********************************************************************************************************************/
  2779. static void s_destroy_operation_pingreq(void *object) {
  2780. if (object == NULL) {
  2781. return;
  2782. }
  2783. struct aws_mqtt5_operation_pingreq *pingreq_op = object;
  2784. aws_mem_release(pingreq_op->allocator, pingreq_op);
  2785. }
  2786. struct aws_mqtt5_operation_pingreq *aws_mqtt5_operation_pingreq_new(struct aws_allocator *allocator) {
  2787. struct aws_mqtt5_operation_pingreq *pingreq_op =
  2788. aws_mem_calloc(allocator, 1, sizeof(struct aws_mqtt5_operation_pingreq));
  2789. if (pingreq_op == NULL) {
  2790. return NULL;
  2791. }
  2792. pingreq_op->allocator = allocator;
  2793. pingreq_op->base.vtable = &s_empty_operation_vtable;
  2794. pingreq_op->base.packet_type = AWS_MQTT5_PT_PINGREQ;
  2795. aws_ref_count_init(&pingreq_op->base.ref_count, pingreq_op, s_destroy_operation_pingreq);
  2796. pingreq_op->base.impl = pingreq_op;
  2797. return pingreq_op;
  2798. }
  2799. /*********************************************************************************************************************
  2800. * Client storage options
  2801. ********************************************************************************************************************/
  2802. int aws_mqtt5_client_options_validate(const struct aws_mqtt5_client_options *options) {
  2803. if (options == NULL) {
  2804. AWS_LOGF_ERROR(AWS_LS_MQTT5_GENERAL, "null mqtt5 client configuration options");
  2805. return aws_raise_error(AWS_ERROR_INVALID_ARGUMENT);
  2806. }
  2807. if (options->host_name.len == 0) {
  2808. AWS_LOGF_ERROR(AWS_LS_MQTT5_GENERAL, "host name not set in mqtt5 client configuration");
  2809. return aws_raise_error(AWS_ERROR_MQTT5_CLIENT_OPTIONS_VALIDATION);
  2810. }
  2811. if (options->bootstrap == NULL) {
  2812. AWS_LOGF_ERROR(AWS_LS_MQTT5_GENERAL, "client bootstrap not set in mqtt5 client configuration");
  2813. return aws_raise_error(AWS_ERROR_MQTT5_CLIENT_OPTIONS_VALIDATION);
  2814. }
  2815. /* forbid no-timeout until someone convinces me otherwise */
  2816. if (options->socket_options != NULL) {
  2817. if (options->socket_options->type == AWS_SOCKET_DGRAM || options->socket_options->connect_timeout_ms == 0) {
  2818. AWS_LOGF_ERROR(AWS_LS_MQTT5_GENERAL, "invalid socket options in mqtt5 client configuration");
  2819. return aws_raise_error(AWS_ERROR_MQTT5_CLIENT_OPTIONS_VALIDATION);
  2820. }
  2821. }
  2822. if (options->http_proxy_options != NULL) {
  2823. if (options->http_proxy_options->host.len == 0) {
  2824. AWS_LOGF_ERROR(AWS_LS_MQTT5_GENERAL, "proxy host name not set in mqtt5 client configuration");
  2825. return aws_raise_error(AWS_ERROR_MQTT5_CLIENT_OPTIONS_VALIDATION);
  2826. }
  2827. if (options->http_proxy_options->port == 0) {
  2828. AWS_LOGF_ERROR(AWS_LS_MQTT5_GENERAL, "proxy port not set in mqtt5 client configuration");
  2829. return aws_raise_error(AWS_ERROR_MQTT5_CLIENT_OPTIONS_VALIDATION);
  2830. }
  2831. }
  2832. /* can't think of why you'd ever want an MQTT client without lifecycle event notifications */
  2833. if (options->lifecycle_event_handler == NULL) {
  2834. AWS_LOGF_ERROR(AWS_LS_MQTT5_GENERAL, "lifecycle event handler not set in mqtt5 client configuration");
  2835. return aws_raise_error(AWS_ERROR_MQTT5_CLIENT_OPTIONS_VALIDATION);
  2836. }
  2837. if (options->publish_received_handler == NULL) {
  2838. AWS_LOGF_ERROR(AWS_LS_MQTT5_GENERAL, "publish received not set in mqtt5 client configuration");
  2839. return aws_raise_error(AWS_ERROR_MQTT5_CLIENT_OPTIONS_VALIDATION);
  2840. }
  2841. if (aws_mqtt5_packet_connect_view_validate(options->connect_options)) {
  2842. AWS_LOGF_ERROR(AWS_LS_MQTT5_GENERAL, "invalid CONNECT options in mqtt5 client configuration");
  2843. return AWS_OP_ERR;
  2844. }
  2845. /* The client will not behave properly if ping timeout is not significantly shorter than the keep alive interval */
  2846. if (options->connect_options->keep_alive_interval_seconds > 0) {
  2847. uint64_t keep_alive_ms = aws_timestamp_convert(
  2848. options->connect_options->keep_alive_interval_seconds, AWS_TIMESTAMP_SECS, AWS_TIMESTAMP_MILLIS, NULL);
  2849. uint64_t one_second_ms = aws_timestamp_convert(1, AWS_TIMESTAMP_SECS, AWS_TIMESTAMP_MILLIS, NULL);
  2850. uint64_t ping_timeout_ms = options->ping_timeout_ms;
  2851. if (ping_timeout_ms == 0) {
  2852. ping_timeout_ms = AWS_MQTT5_CLIENT_DEFAULT_PING_TIMEOUT_MS;
  2853. }
  2854. if (ping_timeout_ms + one_second_ms > keep_alive_ms) {
  2855. AWS_LOGF_ERROR(AWS_LS_MQTT5_GENERAL, "keep alive interval is too small relative to ping timeout interval");
  2856. return AWS_OP_ERR;
  2857. }
  2858. }
  2859. if (options->extended_validation_and_flow_control_options != AWS_MQTT5_EVAFCO_NONE) {
  2860. if (options->connect_options->client_id.len > AWS_IOT_CORE_MAXIMUM_CLIENT_ID_LENGTH) {
  2861. AWS_LOGF_ERROR(
  2862. AWS_LS_MQTT5_GENERAL,
  2863. "AWS IoT Core limits client_id to be less than or equal to %d bytes in length",
  2864. (int)AWS_IOT_CORE_MAXIMUM_CLIENT_ID_LENGTH);
  2865. return aws_raise_error(AWS_ERROR_MQTT5_CLIENT_OPTIONS_VALIDATION);
  2866. }
  2867. }
  2868. return AWS_OP_SUCCESS;
  2869. }
  2870. static void s_log_tls_connection_options(
  2871. struct aws_logger *log_handle,
  2872. const struct aws_mqtt5_client_options_storage *options_storage,
  2873. const struct aws_tls_connection_options *tls_options,
  2874. enum aws_log_level level,
  2875. const char *log_text) {
  2876. AWS_LOGUF(
  2877. log_handle,
  2878. level,
  2879. AWS_LS_MQTT5_GENERAL,
  2880. "id=%p: aws_mqtt5_client_options_storage %s tls options set:",
  2881. (void *)options_storage,
  2882. log_text);
  2883. if (tls_options->advertise_alpn_message && tls_options->alpn_list) {
  2884. AWS_LOGUF(
  2885. log_handle,
  2886. level,
  2887. AWS_LS_MQTT5_GENERAL,
  2888. "id=%p: aws_mqtt5_client_options_storage %s tls options alpn protocol list set to \"%s\"",
  2889. (void *)options_storage,
  2890. log_text,
  2891. aws_string_c_str(tls_options->alpn_list));
  2892. } else {
  2893. AWS_LOGUF(
  2894. log_handle,
  2895. level,
  2896. AWS_LS_MQTT5_GENERAL,
  2897. "id=%p: aws_mqtt5_client_options_storage %s tls options alpn not used",
  2898. (void *)options_storage,
  2899. log_text);
  2900. }
  2901. if (tls_options->server_name) {
  2902. AWS_LOGUF(
  2903. log_handle,
  2904. level,
  2905. AWS_LS_MQTT5_GENERAL,
  2906. "id=%p: aws_mqtt5_client_options_storage %s tls options SNI value set to \"%s\"",
  2907. (void *)options_storage,
  2908. log_text,
  2909. aws_string_c_str(tls_options->server_name));
  2910. } else {
  2911. AWS_LOGUF(
  2912. log_handle,
  2913. level,
  2914. AWS_LS_MQTT5_GENERAL,
  2915. "id=%p: aws_mqtt5_client_options_storage %s tls options SNI not used",
  2916. (void *)options_storage,
  2917. log_text);
  2918. }
  2919. AWS_LOGUF(
  2920. log_handle,
  2921. level,
  2922. AWS_LS_MQTT5_GENERAL,
  2923. "id=%p: aws_mqtt5_client_options_storage %s tls options tls context set to (%p)",
  2924. (void *)options_storage,
  2925. log_text,
  2926. (void *)(tls_options->ctx));
  2927. AWS_LOGUF(
  2928. log_handle,
  2929. level,
  2930. AWS_LS_MQTT5_GENERAL,
  2931. "id=%p: aws_mqtt5_client_options_storage %s tls options handshake timeout set to %" PRIu32,
  2932. (void *)options_storage,
  2933. log_text,
  2934. tls_options->timeout_ms);
  2935. }
  2936. static void s_log_topic_aliasing_options(
  2937. struct aws_logger *log_handle,
  2938. const struct aws_mqtt5_client_options_storage *options_storage,
  2939. const struct aws_mqtt5_client_topic_alias_options *topic_aliasing_options,
  2940. enum aws_log_level level) {
  2941. AWS_LOGUF(
  2942. log_handle,
  2943. level,
  2944. AWS_LS_MQTT5_GENERAL,
  2945. "id=%p: aws_mqtt5_client_options_storage outbound topic aliasing behavior set to %d (%s)",
  2946. (void *)options_storage,
  2947. (int)topic_aliasing_options->outbound_topic_alias_behavior,
  2948. aws_mqtt5_outbound_topic_alias_behavior_type_to_c_string(
  2949. topic_aliasing_options->outbound_topic_alias_behavior));
  2950. AWS_LOGUF(
  2951. log_handle,
  2952. level,
  2953. AWS_LS_MQTT5_GENERAL,
  2954. "id=%p: aws_mqtt5_client_options_storage maximum outbound topic alias cache size set to %" PRIu16,
  2955. (void *)options_storage,
  2956. topic_aliasing_options->outbound_alias_cache_max_size);
  2957. AWS_LOGUF(
  2958. log_handle,
  2959. level,
  2960. AWS_LS_MQTT5_GENERAL,
  2961. "id=%p: aws_mqtt5_client_options_storage inbound topic aliasing behavior set to %d (%s)",
  2962. (void *)options_storage,
  2963. (int)topic_aliasing_options->inbound_topic_alias_behavior,
  2964. aws_mqtt5_inbound_topic_alias_behavior_type_to_c_string(topic_aliasing_options->inbound_topic_alias_behavior));
  2965. AWS_LOGUF(
  2966. log_handle,
  2967. level,
  2968. AWS_LS_MQTT5_GENERAL,
  2969. "id=%p: aws_mqtt5_client_options_storage inbound topic alias cache size set to %" PRIu16,
  2970. (void *)options_storage,
  2971. topic_aliasing_options->inbound_alias_cache_size);
  2972. }
  2973. void aws_mqtt5_client_options_storage_log(
  2974. const struct aws_mqtt5_client_options_storage *options_storage,
  2975. enum aws_log_level level) {
  2976. struct aws_logger *log_handle = aws_logger_get_conditional(AWS_LS_MQTT5_GENERAL, level);
  2977. if (log_handle == NULL) {
  2978. return;
  2979. }
  2980. AWS_LOGUF(
  2981. log_handle,
  2982. level,
  2983. AWS_LS_MQTT5_GENERAL,
  2984. "id=%p: aws_mqtt5_client_options_storage host name set to %s",
  2985. (void *)options_storage,
  2986. aws_string_c_str(options_storage->host_name));
  2987. AWS_LOGUF(
  2988. log_handle,
  2989. level,
  2990. AWS_LS_MQTT5_GENERAL,
  2991. "id=%p: aws_mqtt5_client_options_storage port set to %" PRIu16,
  2992. (void *)options_storage,
  2993. options_storage->port);
  2994. AWS_LOGUF(
  2995. log_handle,
  2996. level,
  2997. AWS_LS_MQTT5_GENERAL,
  2998. "id=%p: aws_mqtt5_client_options_storage client bootstrap set to (%p)",
  2999. (void *)options_storage,
  3000. (void *)options_storage->bootstrap);
  3001. AWS_LOGUF(
  3002. log_handle,
  3003. level,
  3004. AWS_LS_MQTT5_GENERAL,
  3005. "id=%p: aws_mqtt5_client_options_storage socket options set to: type = %d, domain = %d, connect_timeout_ms = "
  3006. "%" PRIu32,
  3007. (void *)options_storage,
  3008. (int)options_storage->socket_options.type,
  3009. (int)options_storage->socket_options.domain,
  3010. options_storage->socket_options.connect_timeout_ms);
  3011. if (options_storage->socket_options.keepalive) {
  3012. AWS_LOGUF(
  3013. log_handle,
  3014. level,
  3015. AWS_LS_MQTT5_GENERAL,
  3016. "id=%p: aws_mqtt5_client_options_storage socket keepalive options set to: keep_alive_interval_sec = "
  3017. "%" PRIu16 ", "
  3018. "keep_alive_timeout_sec = %" PRIu16 ", keep_alive_max_failed_probes = %" PRIu16,
  3019. (void *)options_storage,
  3020. options_storage->socket_options.keep_alive_interval_sec,
  3021. options_storage->socket_options.keep_alive_timeout_sec,
  3022. options_storage->socket_options.keep_alive_max_failed_probes);
  3023. }
  3024. if (options_storage->tls_options_ptr != NULL) {
  3025. s_log_tls_connection_options(log_handle, options_storage, options_storage->tls_options_ptr, level, "");
  3026. }
  3027. if (options_storage->http_proxy_config != NULL) {
  3028. AWS_LOGUF(
  3029. log_handle,
  3030. level,
  3031. AWS_LS_MQTT5_GENERAL,
  3032. "id=%p: aws_mqtt5_client_options_storage using http proxy:",
  3033. (void *)options_storage);
  3034. AWS_LOGUF(
  3035. log_handle,
  3036. level,
  3037. AWS_LS_MQTT5_GENERAL,
  3038. "id=%p: aws_mqtt5_client_options_storage http proxy host name set to " PRInSTR,
  3039. (void *)options_storage,
  3040. AWS_BYTE_CURSOR_PRI(options_storage->http_proxy_options.host));
  3041. AWS_LOGUF(
  3042. log_handle,
  3043. level,
  3044. AWS_LS_MQTT5_GENERAL,
  3045. "id=%p: aws_mqtt5_client_options_storage http proxy port set to %" PRIu16,
  3046. (void *)options_storage,
  3047. options_storage->http_proxy_options.port);
  3048. if (options_storage->http_proxy_options.tls_options != NULL) {
  3049. s_log_tls_connection_options(
  3050. log_handle, options_storage, options_storage->tls_options_ptr, level, "http proxy");
  3051. }
  3052. /* ToDo: add (and use) an API to proxy strategy that returns a debug string (Basic, Adaptive, etc...) */
  3053. if (options_storage->http_proxy_options.proxy_strategy != NULL) {
  3054. AWS_LOGUF(
  3055. log_handle,
  3056. level,
  3057. AWS_LS_MQTT5_GENERAL,
  3058. "id=%p: aws_mqtt5_client_options_storage http proxy strategy set to (%p)",
  3059. (void *)options_storage,
  3060. (void *)options_storage->http_proxy_options.proxy_strategy);
  3061. }
  3062. }
  3063. if (options_storage->websocket_handshake_transform != NULL) {
  3064. AWS_LOGUF(
  3065. log_handle,
  3066. level,
  3067. AWS_LS_MQTT5_GENERAL,
  3068. "id=%p: aws_mqtt5_client_options_storage enabling websockets",
  3069. (void *)options_storage);
  3070. AWS_LOGUF(
  3071. log_handle,
  3072. level,
  3073. AWS_LS_MQTT5_GENERAL,
  3074. "id=%p: aws_mqtt5_client_options_storage websocket handshake transform user data set to (%p)",
  3075. (void *)options_storage,
  3076. options_storage->websocket_handshake_transform_user_data);
  3077. } else {
  3078. AWS_LOGUF(
  3079. log_handle,
  3080. level,
  3081. AWS_LS_MQTT5_GENERAL,
  3082. "id=%p: mqtt5_client_options_storage disabling websockets",
  3083. (void *)options_storage);
  3084. }
  3085. AWS_LOGUF(
  3086. log_handle,
  3087. level,
  3088. AWS_LS_MQTT5_GENERAL,
  3089. "id=%p: aws_mqtt5_client_options_storage session behavior set to %d (%s)",
  3090. (void *)options_storage,
  3091. (int)options_storage->session_behavior,
  3092. aws_mqtt5_client_session_behavior_type_to_c_string(options_storage->session_behavior));
  3093. s_log_topic_aliasing_options(log_handle, options_storage, &options_storage->topic_aliasing_options, level);
  3094. AWS_LOGUF(
  3095. log_handle,
  3096. level,
  3097. AWS_LS_MQTT5_GENERAL,
  3098. "id=%p: aws_mqtt5_client_options_storage extended validation and flow control options set to %d (%s)",
  3099. (void *)options_storage,
  3100. (int)options_storage->extended_validation_and_flow_control_options,
  3101. aws_mqtt5_extended_validation_and_flow_control_options_to_c_string(
  3102. options_storage->extended_validation_and_flow_control_options));
  3103. AWS_LOGUF(
  3104. log_handle,
  3105. level,
  3106. AWS_LS_MQTT5_GENERAL,
  3107. "id=%p: aws_mqtt5_client_options_storage operation queue behavior set to %d (%s)",
  3108. (void *)options_storage,
  3109. (int)options_storage->offline_queue_behavior,
  3110. aws_mqtt5_client_operation_queue_behavior_type_to_c_string(options_storage->offline_queue_behavior));
  3111. AWS_LOGUF(
  3112. log_handle,
  3113. level,
  3114. AWS_LS_MQTT5_GENERAL,
  3115. "id=%p: aws_mqtt5_client_options_storage reconnect jitter mode set to %d",
  3116. (void *)options_storage,
  3117. (int)options_storage->retry_jitter_mode);
  3118. AWS_LOGUF(
  3119. log_handle,
  3120. level,
  3121. AWS_LS_MQTT5_GENERAL,
  3122. "id=%p: mqtt5_client_options_storage reconnect delay min set to %" PRIu64 " ms, max set to %" PRIu64 " ms",
  3123. (void *)options_storage,
  3124. options_storage->min_reconnect_delay_ms,
  3125. options_storage->max_reconnect_delay_ms);
  3126. AWS_LOGUF(
  3127. log_handle,
  3128. level,
  3129. AWS_LS_MQTT5_GENERAL,
  3130. "id=%p: aws_mqtt5_client_options_storage minimum necessary connection time in order to reset the reconnect "
  3131. "delay "
  3132. "set "
  3133. "to %" PRIu64 " ms",
  3134. (void *)options_storage,
  3135. options_storage->min_connected_time_to_reset_reconnect_delay_ms);
  3136. AWS_LOGUF(
  3137. log_handle,
  3138. level,
  3139. AWS_LS_MQTT5_GENERAL,
  3140. "id=%p: aws_mqtt5_client_options_storage ping timeout interval set to %" PRIu32 " ms",
  3141. (void *)options_storage,
  3142. options_storage->ping_timeout_ms);
  3143. AWS_LOGUF(
  3144. log_handle,
  3145. level,
  3146. AWS_LS_MQTT5_GENERAL,
  3147. "id=%p: aws_mqtt5_client_options_storage connack timeout interval set to %" PRIu32 " ms",
  3148. (void *)options_storage,
  3149. options_storage->connack_timeout_ms);
  3150. AWS_LOGUF(
  3151. log_handle,
  3152. level,
  3153. AWS_LS_MQTT5_GENERAL,
  3154. "id=%p: aws_mqtt5_client_options_storage connect options:",
  3155. (void *)options_storage);
  3156. aws_mqtt5_packet_connect_view_log(&options_storage->connect.storage_view, level);
  3157. AWS_LOGUF(
  3158. log_handle,
  3159. level,
  3160. AWS_LS_MQTT5_GENERAL,
  3161. "id=%p: aws_mqtt5_client_options_storage lifecycle event handler user data set to (%p)",
  3162. (void *)options_storage,
  3163. options_storage->lifecycle_event_handler_user_data);
  3164. }
  3165. void aws_mqtt5_client_options_storage_destroy(struct aws_mqtt5_client_options_storage *options_storage) {
  3166. if (options_storage == NULL) {
  3167. return;
  3168. }
  3169. aws_string_destroy(options_storage->host_name);
  3170. aws_client_bootstrap_release(options_storage->bootstrap);
  3171. aws_tls_connection_options_clean_up(&options_storage->tls_options);
  3172. aws_http_proxy_config_destroy(options_storage->http_proxy_config);
  3173. aws_mqtt5_packet_connect_storage_clean_up(&options_storage->connect);
  3174. aws_mem_release(options_storage->allocator, options_storage);
  3175. }
  3176. static void s_apply_zero_valued_defaults_to_client_options_storage(
  3177. struct aws_mqtt5_client_options_storage *options_storage) {
  3178. if (options_storage->min_reconnect_delay_ms == 0) {
  3179. options_storage->min_reconnect_delay_ms = AWS_MQTT5_CLIENT_DEFAULT_MIN_RECONNECT_DELAY_MS;
  3180. }
  3181. if (options_storage->max_reconnect_delay_ms == 0) {
  3182. options_storage->max_reconnect_delay_ms = AWS_MQTT5_CLIENT_DEFAULT_MAX_RECONNECT_DELAY_MS;
  3183. }
  3184. if (options_storage->min_connected_time_to_reset_reconnect_delay_ms == 0) {
  3185. options_storage->min_connected_time_to_reset_reconnect_delay_ms =
  3186. AWS_MQTT5_CLIENT_DEFAULT_MIN_CONNECTED_TIME_TO_RESET_RECONNECT_DELAY_MS;
  3187. }
  3188. if (options_storage->ping_timeout_ms == 0) {
  3189. options_storage->ping_timeout_ms = AWS_MQTT5_CLIENT_DEFAULT_PING_TIMEOUT_MS;
  3190. }
  3191. if (options_storage->connack_timeout_ms == 0) {
  3192. options_storage->connack_timeout_ms = AWS_MQTT5_CLIENT_DEFAULT_CONNACK_TIMEOUT_MS;
  3193. }
  3194. if (options_storage->ack_timeout_seconds == 0) {
  3195. options_storage->ack_timeout_seconds = AWS_MQTT5_CLIENT_DEFAULT_OPERATION_TIMEOUNT_SECONDS;
  3196. }
  3197. if (options_storage->topic_aliasing_options.inbound_alias_cache_size == 0) {
  3198. options_storage->topic_aliasing_options.inbound_alias_cache_size =
  3199. AWS_MQTT5_CLIENT_DEFAULT_INBOUND_TOPIC_ALIAS_CACHE_SIZE;
  3200. }
  3201. if (options_storage->topic_aliasing_options.outbound_alias_cache_max_size == 0) {
  3202. options_storage->topic_aliasing_options.outbound_alias_cache_max_size =
  3203. AWS_MQTT5_CLIENT_DEFAULT_OUTBOUND_TOPIC_ALIAS_CACHE_SIZE;
  3204. }
  3205. }
  3206. struct aws_mqtt5_client_options_storage *aws_mqtt5_client_options_storage_new(
  3207. struct aws_allocator *allocator,
  3208. const struct aws_mqtt5_client_options *options) {
  3209. AWS_PRECONDITION(allocator != NULL);
  3210. AWS_PRECONDITION(options != NULL);
  3211. if (aws_mqtt5_client_options_validate(options)) {
  3212. return NULL;
  3213. }
  3214. struct aws_mqtt5_client_options_storage *options_storage =
  3215. aws_mem_calloc(allocator, 1, sizeof(struct aws_mqtt5_client_options_storage));
  3216. if (options_storage == NULL) {
  3217. return NULL;
  3218. }
  3219. options_storage->allocator = allocator;
  3220. options_storage->host_name = aws_string_new_from_cursor(allocator, &options->host_name);
  3221. if (options_storage->host_name == NULL) {
  3222. goto error;
  3223. }
  3224. options_storage->port = options->port;
  3225. options_storage->bootstrap = aws_client_bootstrap_acquire(options->bootstrap);
  3226. if (options->socket_options != NULL) {
  3227. options_storage->socket_options = *options->socket_options;
  3228. } else {
  3229. options_storage->socket_options.type = AWS_SOCKET_STREAM;
  3230. options_storage->socket_options.connect_timeout_ms = AWS_MQTT5_DEFAULT_SOCKET_CONNECT_TIMEOUT_MS;
  3231. }
  3232. if (options->tls_options != NULL) {
  3233. if (aws_tls_connection_options_copy(&options_storage->tls_options, options->tls_options)) {
  3234. goto error;
  3235. }
  3236. options_storage->tls_options_ptr = &options_storage->tls_options;
  3237. if (!options_storage->tls_options.server_name) {
  3238. struct aws_byte_cursor host_name_cur = aws_byte_cursor_from_string(options_storage->host_name);
  3239. if (aws_tls_connection_options_set_server_name(&options_storage->tls_options, allocator, &host_name_cur)) {
  3240. AWS_LOGF_ERROR(AWS_LS_MQTT5_GENERAL, "Failed to set TLS Connection Options server name");
  3241. goto error;
  3242. }
  3243. }
  3244. }
  3245. if (options->http_proxy_options != NULL) {
  3246. options_storage->http_proxy_config =
  3247. aws_http_proxy_config_new_from_proxy_options(allocator, options->http_proxy_options);
  3248. if (options_storage->http_proxy_config == NULL) {
  3249. goto error;
  3250. }
  3251. aws_http_proxy_options_init_from_config(
  3252. &options_storage->http_proxy_options, options_storage->http_proxy_config);
  3253. }
  3254. options_storage->websocket_handshake_transform = options->websocket_handshake_transform;
  3255. options_storage->websocket_handshake_transform_user_data = options->websocket_handshake_transform_user_data;
  3256. options_storage->publish_received_handler = options->publish_received_handler;
  3257. options_storage->publish_received_handler_user_data = options->publish_received_handler_user_data;
  3258. options_storage->session_behavior = options->session_behavior;
  3259. options_storage->extended_validation_and_flow_control_options =
  3260. options->extended_validation_and_flow_control_options;
  3261. options_storage->offline_queue_behavior = options->offline_queue_behavior;
  3262. options_storage->retry_jitter_mode = options->retry_jitter_mode;
  3263. options_storage->min_reconnect_delay_ms = options->min_reconnect_delay_ms;
  3264. options_storage->max_reconnect_delay_ms = options->max_reconnect_delay_ms;
  3265. options_storage->min_connected_time_to_reset_reconnect_delay_ms =
  3266. options->min_connected_time_to_reset_reconnect_delay_ms;
  3267. options_storage->ping_timeout_ms = options->ping_timeout_ms;
  3268. options_storage->connack_timeout_ms = options->connack_timeout_ms;
  3269. options_storage->ack_timeout_seconds = options->ack_timeout_seconds;
  3270. if (options->topic_aliasing_options != NULL) {
  3271. options_storage->topic_aliasing_options = *options->topic_aliasing_options;
  3272. }
  3273. if (aws_mqtt5_packet_connect_storage_init(&options_storage->connect, allocator, options->connect_options)) {
  3274. goto error;
  3275. }
  3276. options_storage->lifecycle_event_handler = options->lifecycle_event_handler;
  3277. options_storage->lifecycle_event_handler_user_data = options->lifecycle_event_handler_user_data;
  3278. options_storage->client_termination_handler = options->client_termination_handler;
  3279. options_storage->client_termination_handler_user_data = options->client_termination_handler_user_data;
  3280. s_apply_zero_valued_defaults_to_client_options_storage(options_storage);
  3281. return options_storage;
  3282. error:
  3283. aws_mqtt5_client_options_storage_destroy(options_storage);
  3284. return NULL;
  3285. }
  3286. struct aws_mqtt5_operation_disconnect *aws_mqtt5_operation_disconnect_acquire(
  3287. struct aws_mqtt5_operation_disconnect *disconnect_op) {
  3288. if (disconnect_op != NULL) {
  3289. aws_mqtt5_operation_acquire(&disconnect_op->base);
  3290. }
  3291. return disconnect_op;
  3292. }
  3293. struct aws_mqtt5_operation_disconnect *aws_mqtt5_operation_disconnect_release(
  3294. struct aws_mqtt5_operation_disconnect *disconnect_op) {
  3295. if (disconnect_op != NULL) {
  3296. aws_mqtt5_operation_release(&disconnect_op->base);
  3297. }
  3298. return NULL;
  3299. }