eGospodarka.pl
eGospodarka.pl poleca

eGospodarka.plGrupypl.misc.elektronika › Biblioteka MQTT i dziwny kod w C
Ilość wypowiedzi w tym wątku: 25

  • 1. Data: 2022-08-08 19:14:27
    Temat: Biblioteka MQTT i dziwny kod w C
    Od: Atlantis <m...@w...pl>

    Wróciłem ostatnio do jednego ze swoich starych projektów, zrealizowanych
    w oparciu o PIC32. Chciałem dodać do niego jedną dość ważną
    funkcjonalność - możliwość wrzucania danych za pomocą MQTT.
    Udało mi się znaleźć bibliotekę napisaną w oparciu o starzy stos
    Microchipa (biblioteki MLA), który użyłem w swoim projekcie. Zależało mi
    na tym, bo nie chciałem przenosić całego kodu na nowsze biblioteki Harmony.

    https://github.com/dominicusplatus/mqttx

    Potrzeba było trochę eksperymentów, jednak w końcu udało mi się
    uruchomić bibliotekę. Dość szybko okazało się, że daleko jej do ideału.
    Działa całkiem nieźle, jeśli serwer ma wyłączoną autoryzację, albo w
    pakiecie CONNECT wysyłamy prawidłowy login i hasło.
    Problemy zaczynają się w momencie, gdy próbujemy podać nieprawidłowe
    dane do logowania. Sprawdziłem komunikację Wiresharkiem - serwer
    odpowiada prawidłowo, jednak klient zupełnie to ignoruje, przystępując
    do wysyłania komunikatu. Po paru podejściach powoduje to wykrzaczenie
    programu i reset mikrokontrolera.

    Przyjrzałem się bliżej kodowi i znalazłem przyczynę. Podczas parsowania
    pakietu CONNACK wywoływana jest funkcja MQTTReadPacket(), która pobiera
    dane z socketa do bufora MQTTBuffer. Potem jednak kod sprawdza stan stan
    bajtu rxBF[1], gdzie spodziewa się znaleźć Return Code i na jego
    podstawie podjąć decyzję do co dalszego działania.

    Problem polega na tym, że w obecnej wersji kodu tablica rxBF nie jest
    nigdzie wykorzystywana. Nie trafiają do niej żadne dane (a więc również
    i pakiet CONNACK) i cały czas znajdują się w niej same zera. Program
    interpretuje więc odczytaną wartość jako Connection Accepted i
    przechodzi do dalszych czynności.

    Chciałem się bliżej przyjrzeć funkcji MQTTReadPacket() i tutaj trafiłem
    do króliczej nory. ;)

    Okazuje się, że została ona zdefiniowana i zdeklarowana z pustą listą
    parametrów (bez void), podobnie jak to się robi z bezparametrowymi
    funkcjami w C++. Widzę jednak, że w paru miejscach w kodzie funkcja
    przyjmuje parametr w postaci wskaźnika na BYTE, przykładowo:

    BYTE llen;
    WORD len= MQTTReadPacket(&llen);

    Potem zawartość takiej zmiennej jest wykorzystywana w kodzie jako
    element indeksu tablicy MQTTBuffer - również w tych częściach kodu,
    które działały prawidłowo. Szybkie poszukiwania w internecie ujawniły,
    że możliwość zdeklarowania pustej listy argumentów to historyczna
    zaszłość. Wszyscy przestrzegają przed robieniem tego. Natomiast nigdzie
    nie mogę znaleźć informacji o tym, w jaki sposób to działa i co
    właściwie robią te kawałki kodu. Ktoś ma jakiś pomysł?


  • 2. Data: 2022-08-08 21:00:45
    Temat: Re: Biblioteka MQTT i dziwny kod w C
    Od: heby <h...@p...onet.pl>

    On 08/08/2022 19:14, Atlantis wrote:
    > Natomiast nigdzie
    > nie mogę znaleźć informacji o tym, w jaki sposób to działa i co
    > właściwie robią te kawałki kodu. Ktoś ma jakiś pomysł?

    Podziel się większym kontekstem tego kodu.


  • 3. Data: 2022-08-08 22:00:34
    Temat: Re: Biblioteka MQTT i dziwny kod w C
    Od: jacek <j...@f...pl>

    Atlantis <m...@w...pl> wrote:
    > Wróciłem ostatnio do jednego ze swoich starych projektów, zrealizowanych
    > w oparciu o PIC32. Chciałem dodać do niego jedną dość ważną
    > funkcjonalność - możliwość wrzucania danych za pomocą MQTT.
    > Udało mi się znaleźć bibliotekę napisaną w oparciu o starzy stos
    > Microchipa (biblioteki MLA), który użyłem w swoim projekcie. Zależało mi
    > na tym, bo nie chciałem przenosić całego kodu na nowsze biblioteki Harmony.
    >
    > https://github.com/dominicusplatus/mqttx
    >
    > Potrzeba było trochę eksperymentów, jednak w końcu udało mi się
    > uruchomić bibliotekę. Dość szybko okazało się, że daleko jej do ideału.
    > Działa całkiem nieźle, jeśli serwer ma wyłączoną autoryzację, albo w
    > pakiecie CONNECT wysyłamy prawidłowy login i hasło.
    > Problemy zaczynają się w momencie, gdy próbujemy podać nieprawidłowe
    > dane do logowania. Sprawdziłem komunikację Wiresharkiem - serwer
    > odpowiada prawidłowo, jednak klient zupełnie to ignoruje, przystępując
    > do wysyłania komunikatu. Po paru podejściach powoduje to wykrzaczenie
    > programu i reset mikrokontrolera.
    >
    > Przyjrzałem się bliżej kodowi i znalazłem przyczynę. Podczas parsowania
    > pakietu CONNACK wywoływana jest funkcja MQTTReadPacket(), która pobiera
    > dane z socketa do bufora MQTTBuffer. Potem jednak kod sprawdza stan stan
    > bajtu rxBF[1], gdzie spodziewa się znaleźć Return Code i na jego
    > podstawie podjąć decyzję do co dalszego działania.
    >
    > Problem polega na tym, że w obecnej wersji kodu tablica rxBF nie jest
    > nigdzie wykorzystywana. Nie trafiają do niej żadne dane (a więc również
    > i pakiet CONNACK) i cały czas znajdują się w niej same zera. Program
    > interpretuje więc odczytaną wartość jako Connection Accepted i
    > przechodzi do dalszych czynności.
    >
    > Chciałem się bliżej przyjrzeć funkcji MQTTReadPacket() i tutaj trafiłem
    > do króliczej nory. ;)
    >
    > Okazuje się, że została ona zdefiniowana i zdeklarowana z pustą listą
    > parametrów (bez void), podobnie jak to się robi z bezparametrowymi
    > funkcjami w C++. Widzę jednak, że w paru miejscach w kodzie funkcja
    > przyjmuje parametr w postaci wskaźnika na BYTE, przykładowo:
    >
    > BYTE llen;
    > WORD len= MQTTReadPacket(&llen);
    >
    > Potem zawartość takiej zmiennej jest wykorzystywana w kodzie jako
    > element indeksu tablicy MQTTBuffer - również w tych częściach kodu,
    > które działały prawidłowo. Szybkie poszukiwania w internecie ujawniły,
    > że możliwość zdeklarowania pustej listy argumentów to historyczna
    > zaszłość. Wszyscy przestrzegają przed robieniem tego. Natomiast nigdzie
    > nie mogę znaleźć informacji o tym, w jaki sposób to działa i co
    > właściwie robią te kawałki kodu. Ktoś ma jakiś pomysł?
    >

    Nie możesz po prostu poprawić tego kodu.
    Ja, implementujące mqtt, po prostu powyginalem jakaś niedorobioną
    bibliotekę i będzie git. Przynajmniej w zakresie w jakim tego
    potrzebowalem.

    jp


  • 4. Data: 2022-08-08 23:43:57
    Temat: Re: Biblioteka MQTT i dziwny kod w C
    Od: Atlantis <m...@w...pl>

    On 08.08.2022 21:00, heby wrote:

    > Podziel się większym kontekstem tego kodu.

    W poprzedniej wiadomości był link do repozytorium na GitHubie. Tam jest
    całość.


  • 5. Data: 2022-08-09 07:13:17
    Temat: Re: Biblioteka MQTT i dziwny kod w C
    Od: JDX <j...@o...pl>

    On 08.08.2022 19:14, Atlantis wrote:
    [...]
    > BYTE llen;
    > WORD len= MQTTReadPacket(&llen);
    >
    Ewidentny błąd - pokazuje dlaczego należy kompilować z -Wall (oraz
    ewentualnie -pedantic) i nie ignorować ostrzeżeń. Aczkolwiek w
    przytoczonym kontekście nie ma znaczenia - zmienna llen ma zasięg
    lokalny ograniczony do wnętrza if-a i poza wywołaniem MQTTReadPacket()
    nigdzie nie jest tam później używana.

    > Potem zawartość takiej zmiennej jest wykorzystywana w kodzie jako
    > element indeksu tablicy MQTTBuffer - również w tych częściach kodu,
    > które działały prawidłowo. Szybkie poszukiwania w internecie ujawniły,
    > że możliwość zdeklarowania pustej listy argumentów to historyczna
    > zaszłość. Wszyscy przestrzegają przed robieniem tego. Natomiast nigdzie
    > nie mogę znaleźć informacji o tym, w jaki sposób to działa i co
    > właściwie robią te kawałki kodu. Ktoś ma jakiś pomysł?
    Nie jestem pewny co oznaczają ,,te kawałki kodu", ale w ramach testu
    proponuję odnaleźć ten kontekst:

    if(MQTTAvailable()) {
    BYTE llen;
    WORD len = MQTTReadPacket(&llen);
    WORD msgId = 0;
    BYTE *payload;

    i zaraz po deklaracjach zmiennych dopisać llen = len.

    No i proponuję też zamienić
    switch(rxBF[1]) { //MQTTBuffer
    na
    switch(MQTTBuffer[1]) { //MQTTBuffer



  • 6. Data: 2022-08-09 08:36:38
    Temat: Re: Biblioteka MQTT i dziwny kod w C
    Od: Atlantis <m...@w...pl>

    On 09.08.2022 07:13, JDX wrote:

    > Ewidentny błąd - pokazuje dlaczego należy kompilować z -Wall (oraz
    > ewentualnie -pedantic) i nie ignorować ostrzeżeń. Aczkolwiek w

    Przy próbie kompilacji z -Wall kompilator (xc32-gcc) wywala kilka błędów
    w bibliotece GCC, ale dotyczą one takich rzeczy jak niewykorzystane
    zmienne albo niejawne rzutowanie z char* na BYTE* w argumencie funkcji.
    Do tej konkretnej konstrukcji z pustą listą parametrów się akurat nie
    czepia.


    > przytoczonym kontekście nie ma znaczenia - zmienna llen ma zasięg
    > lokalny ograniczony do wnętrza if-a i poza wywołaniem MQTTReadPacket()
    > nigdzie nie jest tam później używana.

    Chodziło mi o inne miejsce - od linii 787. Tam zmienna llen jest
    przekazywana do funkcji MQTTReadPacket w taki sam sposób, a potem bierze
    udział w wyliczaniu indeksów do MQTTBuffer.
    Chociaż z drugiej strony wszystkie z tych operacji to sumowanie. Zmienna
    llen jest zmienną lokalną, a wiec jest domyślnie inicjalizowana
    wartością 0. Jeśli przekazanie jej przez wskaźnik do funkcji o pustej
    liście parametrów nie ma żadnego wpływu na jej wartość, to nie będzie
    też miało na późniejsze wyliczenia.
    Czyżby pozostałość po jakichś wcześniejszych wersjach kodu, gdzie
    faktycznie w parametrze był wskaźnik? A potem autor to przepisał, na
    wersję bezparametrową i zamiast dać void wyczyścił listę parametrów, nie
    poprawiając wcześniejszych wywołań?


    > No i proponuję też zamienić
    >     switch(rxBF[1]) {   //MQTTBuffer
    > na
    >     switch(MQTTBuffer[1]) {   //MQTTBuffer

    To była pierwsza rzecz jaką sprawdziłem. Wychodzi na to, że:
    1) MQTTReadPacket() wołane bezpośrednio przed tym switchem zwraca 2.
    2) MQTTBuffer[01] w tym miejscu zwraca wartość 0x02. Zawsze, niezależnie
    od tego czy dane do logowania były prawidłowe, czy nie. Postanowiłem
    więc sprawdzić co mamy w MQTTBuffer[0] i sprawa się rozjaśniła - mamy
    tam 0x20. Razem te dwa bajty stanowią więc prawidłowy nagłówek
    wiadomości CONNACK. Dalej powinny iść jeszcze dwa bajty, z których
    ostatni stanowi reurn code informujący o stanie autoryzacji. Serwer
    istotnie wysyła całą wiadomość - sprawdziłem tcpdump i wiresharkiem.
    3) Spróbowałem więc po prostu sprawdzać MQTTBuffer[3] ale niestety - nie
    znajduję tam return code. Wygląda to faktycznie tak, jakby
    MQTTReadPacket w tym miejscu odczytywało tylko dwa pierwsze bajty, co
    zgadzałoby się z wartością zwracaną przez funkcję.


  • 7. Data: 2022-08-09 09:47:51
    Temat: Re: Biblioteka MQTT i dziwny kod w C
    Od: "Grzegorz Niemirowski" <g...@g...net>

    Atlantis <m...@w...pl> napisał(a):
    > Zmienna llen jest zmienną lokalną, a wiec jest domyślnie inicjalizowana
    > wartością 0.

    Odwrotnie. Nie jest inicjalizowana bo nie jest statyczna. Inicjalizacja
    domyślna zmiennych odbywa się raz, przed uruchomieniem main(). Zmienne
    automatyczne, alokowane na stosie, mają de facto przypadkowe wartości.

    --
    Grzegorz Niemirowski
    https://www.grzegorz.net/


  • 8. Data: 2022-08-09 10:16:27
    Temat: Re: Biblioteka MQTT i dziwny kod w C
    Od: JDX <j...@o...pl>

    On 09.08.2022 08:36, Atlantis wrote:
    [...]
    > Czyżby pozostałość po jakichś wcześniejszych wersjach kodu, gdzie
    > faktycznie w parametrze był wskaźnik? A potem autor to przepisał, na
    > wersję bezparametrową i zamiast dać void wyczyścił listę parametrów, nie
    > poprawiając wcześniejszych wywołań?
    Tak, na to to właśnie dla mnie wygląda. Widać to zresztą po niektórych
    komentarzach w kodzie.

    > MQTTReadPacket w tym miejscu odczytywało tylko dwa pierwsze bajty, co
    > zgadzałoby się z wartością zwracaną przez funkcję.
    Jak dla mnie to ta funkcja to jakieś totalne, niedorobione gówno.
    Prowizorka znaczy się. Tutaj bym szukał błędu. Kody stanów w switch-u
    zakodowane na twardo, a nie za pomocą enumów/makr - jak mniemam chodzi o
    kody wymienione w enum-ie na początku. Stany zmieniane za pomocą
    m_state++ czy m_state=3 zamiast m_state=NAZWA_KOLEJNEGO_STANU - aż się
    prosi o kłopoty. Nie chce mi się analizować tego kodu, ale wydaje mi
    się, że nie wszystkie stany są obsługiwane.


  • 9. Data: 2022-08-09 10:29:31
    Temat: Re: Biblioteka MQTT i dziwny kod w C
    Od: Atlantis <m...@w...pl>

    On 09.08.2022 09:47, Grzegorz Niemirowski wrote:

    > Odwrotnie. Nie jest inicjalizowana bo nie jest statyczna. Inicjalizacja
    > domyślna zmiennych odbywa się raz, przed uruchomieniem main(). Zmienne
    > automatyczne, alokowane na stosie, mają de facto przypadkowe wartości.

    Masz rację, moja pomyłka.
    W ramach eksperymentu usunąłem z kodu wszelkie przypadki zmiennych
    przekazywanych do MQTTReadPacket() przez wskaźnik na pustej liście
    parametrów. Takich sytuacji było dosłownie tylko kilka.
    Najbardziej istotna wydawała się sytuacja, gdzie taka zmienna llen była
    potem wykorzystywana do wyliczania indeksów tablicy MQTTBuffer. Usunąłem
    wszelkie odwołania do tej zmiennej, ustawiłem parametr MQTTReadPacket na
    void i skompilowałem program. Wszystko działa tak jak poprzednio - ani
    lepiej, ani gorzej.
    Wcześniej założyłem, że musi się tam dziać jakaś dziwna "ezoteryczna
    magia" wynikająca ze specyfiki języka i w jakiś niewidoczny w kodzie
    sposób odpowiednia wartość trafia jednak do zmiennej llen i wszystko
    działa jak powinno.
    Być może jednak po prostu w moim przypadki ten "if" nie jest nigdy
    wywoływany, więc program nie wchodził nigdy w tę gałąź i losowe wartości
    ze stosu trafiające do llen nie dawały o sobie znać.


  • 10. Data: 2022-08-09 10:53:41
    Temat: Re: Biblioteka MQTT i dziwny kod w C
    Od: Atlantis <m...@w...pl>

    On 09.08.2022 10:16, JDX wrote:

    > Jak dla mnie to ta funkcja to jakieś totalne, niedorobione gówno.
    > Prowizorka znaczy się. Tutaj bym szukał błędu. Kody stanów w switch-u
    > zakodowane na twardo, a nie za pomocą enumów/makr - jak mniemam chodzi o
    > kody wymienione w enum-ie na początku. Stany zmieniane za pomocą
    > m_state++ czy m_state=3 zamiast m_state=NAZWA_KOLEJNEGO_STANU - aż się
    > prosi o kłopoty. Nie chce mi się analizować tego kodu, ale wydaje mi
    > się, że nie wszystkie stany są obsługiwane.

    Też się skłaniam ku tej hipotezie. Będę musiał przyjrzeć się temu
    bliżej, bo na razie wygląda na to, że ta funkcja nie jest kompatybilna z
    wiadomością CONNACK i po natrafieniu na nią nie czyta wszystkiego, a
    jedynie pobiera dwa pierwsze bajty.
    Autor nie zauważył tego, bo przez przypadek tak się złożyło, że w
    switch/case sprawdzał wartość komórki pamięci, która zawsze miała
    wartość 0x00, więc zawsze wyglądało to tak, jakby połączenie zostało
    autoryzowane. Najwyraźniej nie przetestował nigdy działania biblioteki z
    błędnym loginem/hasłem.

    Generalnie i tak prościej będzie usunąć z tego błędy o trochę wyczyścić
    kod, niż pisać swoją własną bibliotekę albo portować inną pod stos
    TCP/IP MLA od Microchipa...

    To prawdopodobnie nie będzie ostatnia rzecz, bo w Wiresharku widzę
    jeszcze jakieś retransmisje przy zamykaniu połączenia TCP po zakończonej
    transmisji, ale najpierw chciałem się uporać z problemem z autoryzacją,

strony : [ 1 ] . 2 . 3


Szukaj w grupach

Szukaj w grupach

Eksperci egospodarka.pl

1 1 1

Wpisz nazwę miasta, dla którego chcesz znaleźć jednostkę ZUS.

Wzory dokumentów

Bezpłatne wzory dokumentów i formularzy.
Wyszukaj i pobierz za darmo: