Das IOT-Testgerät MSP430F5529 + CC3100 reagiert nur auf einige Testwebsites

8

Vor kurzem habe ich an einem IoT-Projekt mit einem MSP430F5529-Mikrocontroller und einem CC3100-Netzwerkprozessor von Texas Instrument gearbeitet. Zur Auswertung verwende ich die Startrampe MSP430F5529 und das Boosterpack CC3100 . Ich versuche, das Gerät dazu zu bringen, eine Verbindung zur Cloud herzustellen. Ich habe die CC3100 Get Weather- Beispielanwendung erfolgreich implementiert, die eine Verbindung zu www.openweathermap.org herstellt . Dieses Beispiel stammt aus CC3100 SDK-Beispielanwendungen . Das Programm erhält und antwortet erfolgreich von der Website www.openweathermap.org . Die Anwendung verwendet die GET-Methode, um eine Anfrage von der Website zu stellen.

Ich habe den Code auch erfolgreich gegen www.mocky.io getestet . Das Gerät erhält eine Statuscode 200 OK-Antwort. Wenn ich jedoch gegen requestb.in test site teste, erhalte ich weder einen 408 Timeout-Fehlerantwortcode noch einen URL-Umleitungsantwortcode von 302.

#define WEATHER_SERVER  "api.openweathermap.org"
#define TEST_SERVER  "requestb.in"
//#define TEST_SERVER  "www.mocky.io"

#define PREFIX_BUFFER   "GET /data/2.5/weather?q="
#define POST_BUFFER     "&APPID=xxxxxxxxxxxxxxxxxx&mode=xml&units=imperial HTTP/1.1\r\nHost:api.openweathermap.org\r\nAccept: */"
#define POST_BUFFER2    "*\r\n\r\n"

#define PREFIX_BUFFER_TEST    "GET /1m75pgt1"
#define POST_BUFFER_TEST_1    " HTTP/1.1\r\nHost:requestb.in\r\nAccept: */"
#define POST_BUFFER_TEST_2    "\r\n\r\n"*

//#define PREFIX_BUFFER_TEST      "GET /v2/5967a65d1100007d16b6c2b4"
//#define POST_BUFFER_TEST_1    " HTTP/1.1\r\nHost:www.mocky.io\r\nAccept: */"
//#define POST_BUFFER_TEST_2    "\r\n\r\n"*

Nachfolgend finden Sie die wichtigsten Informationen zu einigen Einrichtungsbedingungen. Ein Teil des Fehlerbehandlungscodes wurde der Kürze halber entfernt.

 int main(int argc, char** argv)
{
    _i32 retVal = -1;

    retVal = initializeAppVariables();
    ASSERT_ON_ERROR(retVal);



    /* Stop WDT and initialize the system-clock of the MCU */
    stopWDT();
    initClk();


    /*
     * Following function configures the device to default state by cleaning
     * the persistent settings stored in NVMEM (viz. connection profiles &
     * policies, power policy etc)
     *
     * Applications may choose to skip this step if the developer is sure
     * that the device is in its default state at start of application
     *
     * Note that all profiles and persistent settings that were done on the
     * device will be lost
     */
    retVal = configureSimpleLinkToDefaultState();


    /*
     * Assumption is that the device is configured in station mode already
     * and it is in its default state
     */
    retVal = sl_Start(0, 0, 0);

    /* Connecting to WLAN AP */
    retVal = establishConnectionWithAP();

    retVal = getCredentials();

    retVal = disconnectFromAP();

    return 0;
}

Unten finden Sie den Code getCredentials (), mit dem Aufrufdaten abgerufen werden.

<!-- language: lang-c -->
static _i32 getCredentials()
{
    _i32 retVal = -1;

    pal_Strcpy((char *)g_DeviceData.HostName, TEST_SERVER);

    retVal = getHostIP_Device();

    g_DeviceData.SockID = createConnection();
    ASSERT_ON_ERROR(g_DeviceData.SockID);

    retVal = getData();
    ASSERT_ON_ERROR(retVal);

    retVal = sl_Close(g_DeviceData.SockID);
    ASSERT_ON_ERROR(retVal);

    return 0;
}

Unten ist eine Funktion getdata () , bei der der Fehler angezeigt wird.

/*!
    \brief This function Obtains the required data from the server

    \param[in]      none

    \return         0 on success, -ve otherwise

    \note

    \warning
*/
static _i32 getData()
{
    _u8 *p_startPtr = NULL;
    _u8 *p_endPtr = NULL;
    _u8* p_bufLocation = NULL;
    _i32 retVal = -1;

    pal_Memset(g_DeviceData.Recvbuff, 0, sizeof(g_DeviceData.Recvbuff));

    /* Puts together the HTTP GET string. */
    p_bufLocation = g_DeviceData.SendBuff;

    pal_Strcpy(p_bufLocation, PREFIX_BUFFER_TEST);
    p_bufLocation += pal_Strlen(PREFIX_BUFFER_TEST);

    pal_Strcpy(p_bufLocation, POST_BUFFER_TEST_1);
    p_bufLocation += pal_Strlen(POST_BUFFER_TEST_1);

    pal_Strcpy(p_bufLocation, POST_BUFFER_TEST_2);

    /* Send the HTTP GET string to the open TCP/IP socket. */
    retVal = sl_Send(g_DeviceData.SockID, g_DeviceData.SendBuff, pal_Strlen(g_DeviceData.SendBuff), 0);
    if(retVal != pal_Strlen(g_DeviceData.SendBuff))
        ASSERT_ON_ERROR(HTTP_SEND_ERROR);

    /* Receive response */
    retVal = sl_Recv(g_DeviceData.SockID, &g_DeviceData.Recvbuff[0], MAX_SEND_RCV_SIZE, 0);
    if(retVal <= 0)
        ASSERT_ON_ERROR(HTTP_RECV_ERROR);

    g_DeviceData.Recvbuff[pal_Strlen(g_DeviceData.Recvbuff)] = '\0';
    return SUCCESS;
}

Die Sicherheit für den Access Point ist eingerichtet als

#define SEC_TYPE        SL_SEC_TYPE_WPA_WPA2    /* Security type of the Access point */

Schließlich gibt es nur wenige mit CC3100 hergestellte POC-Sensorgeräte, die Daten in die Cloud übertragen müssen. Der Einfachheit halber verwenden wir das Boosterpack. Schließlich müssen die POC-Sensorgeräte über WLAN mit der Cloud kommunizieren.

user8055
quelle
Ich stimme dafür, diese Frage als nicht zum Thema gehörend zu schließen, da das eigentliche Problem der Frage die grundlegende HTTP-Nutzung und in geringerem Maße eine bestimmte eingebettete Plattform ist, nicht das Internet der Dinge. Daher besteht der Pool der Gemeinsamkeiten bei anderen HTTP-Fragen Erstens und überhaupt nicht wirklich zu anderen IoT-Fragen.
Chris Stratton
1
Zu Ihrer Information, die spezifische requestb.in-Instanz in Ihrem Code hat anscheinend eine Zeitüberschreitung und jetzt 404 beim Zugriff über HTTP über TLS mit SNI, wie dies für derzeit gültige funktioniert.
Chris Stratton
@mico, mir ist aufgefallen, dass du deine Antwort entfernt hast. Sie haben auch erwähnt, dass Sie http ein "s" hinzufügen. Ich bin mir nicht sicher, wie ich Ihren Vorschlag erreichen kann. Können Sie mir bitte einige Einblicke geben?
user8055
@ ChrisStratton, Entschuldigung, hören Sie, dass Sie abstimmen, um diese Fragen zu schließen. Können Sie mir bitte eine gute Q & A-Seite empfehlen, um diese Frage zu stellen?
user8055
Erhalten Sie diese 302 und 408 Nachrichten oder nicht? Wenn nicht, welche Nachrichten erhalten Sie dann?
Mico

Antworten:

5

Der Unterschied besteht darin, dass für die Site requestb.in HTTP über TLS mit SNI erforderlich ist

Dies ist eine ziemlich komplexe HTTP / HTTPS- Protokoll- und Sicherheitsfrage , die wahrscheinlich an anderer Stelle im SE-System besser behandelt wird und sich hauptsächlich auf Details des requestb.inDienstes bezieht, gegen den Sie testen, und nicht auf das IoT-Projekt, das Sie möglicherweise gerade ausführen. Aber solange es hier bleibt ...


Debuggen des Antwortcodes requestb.in beim Versuch von HTTP auf Port 80

Du sagtest:

Wenn ich jedoch gegen requestb.in test site teste, erhalte ich weder einen 408 Timeout-Fehlerantwortcode noch einen URL-Umleitungsantwortcode von 302.

Mal sehen was passiert:

curl -i http://requestb.in/xxxxxxxx
HTTP/1.1 301 Moved Permanently
Location: https://requestb.in/xxxxxxxx

Der HTTP-Status 301 lautet "Permanent verschoben", während der erwartete 302 manchmal für eine temporäre Umleitung verwendet wird. Da sie wahrscheinlich nicht vorhaben, HTTP jemals an einem einfachen TCP-Socket an Port 80 verwenden zu lassen, ist die permanente Weiterleitung, die sie senden, die korrektere Antwort.

Es wäre viel hilfreicher gewesen, wenn Sie den Statuscode erfasst hätten, der gesendet wurde, anstatt nur zwei aufzulisten, die nicht gesendet wurden

Auf jeden Fall sagt der Server, dass wir HTTPS verwenden müssen.


Was müssten Sie also tun, um über HTTPS eine Verbindung zum Server herzustellen?

Grundsätzlich bedeutet HTTPS einfach, HTTP über eine mit TLS (oder früher SSL) gesicherte Verbindung zu sprechen, anstatt dies über einen einfachen TCP-Socket zu tun.

Ihr CC3100 unterstützt TLS und SSL . Es gibt nur wenige Informationen zum Ändern eines der HTTP-Client-Beispiele des SDK, um eine HTTPS-Verbindung herzustellen, indem stattdessen ein sicherer Kanal unter http://processors.wiki.ti.com/index.php bereitgestellt wird / CC3100_HTTP_Client

In diesem Fall ist requestb.indies jedoch möglicherweise nicht ausreichend.

Wenn Sie eine sehr einfache GET-Anforderung in den s_clientBefehl von openssl leiten (oder dasselbe auf dem CC3100 tun)

(echo -en "GET /xxxxxxxx HTTP/1.1\nHost: requestb.in\n\n" ; sleep 10) | \
openssl s_client -connect requestb.in:443

(Damit sleepsoll openssl auf eine Antwort warten, anstatt am Ende der Eingabe aufzulegen.)

Sie würden einen seltsamen Fehler erhalten:

SSL-Routinen: SSL23_GET_SERVER_HELLO: sslv3-Alarm-Handshake-Fehler

Möglicherweise hat dies etwas mit SSL- oder TLS-Versionen zu tun, aber tatsächlich ist dies darauf zurückzuführen, requestb.indass etwas namens Server Name Indication (Wikipedia) erforderlich ist . Dies bedeutet effektiv, dass Sie dem SSL-Stack mitteilen müssen, unter welchem Servernamen er sich authentifizieren soll.

Wenn Sie mit den Befehlszeilendemonstrationen fortfahren, fügen Sie einfach ein -servernameArgument hinzu:

(echo -en "GET /xxxxxxxx HTTP/1.1\nHost: requestb.in\n\n" ; sleep 10) |\
openssl s_client -connect requestb.in:443 -servername requestb.in

Wenn dies mit dem URL-Hash einer gültigen requestb.in-Instanz erfolgt, wird ein Ergebnis erstellt, das im Protokollbereich des Browsers angezeigt wird, der das erstellt hat.


Implementieren der Servernamenanzeige (SNI) auf dem CC3xxx

Es gibt einige Forum - Beiträge darauf hindeutet , dass die TLS - Implementierung auf der CC3xxx hat SNI nicht unterstützt wird , und dass es keine konkreten Pläne , dies zu addieren; Sie können jedoch überprüfen, ob dies immer noch der Fall ist.

Es ist jedoch wichtig, sich daran zu erinnern, dass es sich um einen Baum von Netzwerkebenen handelt:

WiFi
  IP packets
    TCP session
      TLS session
        HTTP protocol

Da Sie mit dem CC3100 TCP sprechen können (und dies tatsächlich in Ihrem vorhandenen Code getan haben), können Sie Ihre eigene TLS-Implementierung mit SNI-Unterstützung "mitbringen". In diesem Blogbeitrag wird beispielsweise die Portierung der Bibliothek mbed TLS (ehemals PolarSSL) auf das CC3xxx erläutert und SNI als Funktion erwähnt.

TL; DR

requestb.inist ein herausforderndes Ziel, da Sie HTTP über eine mit TLS gesicherte Sitzung sprechen und die Servernamenanzeige implementieren müssen . Wenn die Kommunikation mit diesem Host nicht Teil Ihres endgültigen Projekts ist, ist es möglicherweise besser, einfach zu den Hosts zu wechseln, die für die Verwendung mit minimalen eingebetteten Clients auf IoT-Geräten vorgesehen sind, um die Arbeit zu vereinfachen SNI nicht verwenden.

Es wird auch weitaus effizienter, wenn Sie sich angewöhnen, die Details von Problemen zu erfassen, auf die Sie stoßen. Die eingebettete Entwicklung ist immer schwierig zu debuggen. Je weniger Informationen über Fehler Sie über die Protokollierung oder einen Debugger erfassen, desto mehr Zeit wird für das Erraten aufgewendet .

Chris Stratton
quelle
Sieht nach einer guten Antwort aus, ist aber für mich unverständlich. Ich hoffe, dass ich in naher Zukunft dieses Niveau an fundiertem Wissen erreichen kann. Aber vielen Dank für die Antwort.
user8055
1
Die SNI-Anforderung macht es in der Tat kompliziert - meine Empfehlung wäre, requestb.in zu überspringen, sich auf die Anforderungen zu konzentrieren, mit denen Sie in Ihrem realen Projekt tatsächlich sprechen möchten, und bei Bedarf einen Spottdienst zu finden, der dem ähnlicher ist diese Anforderung.
Chris Stratton
Wenn ich dies jetzt lese und zwei meiner Wettbewerbsanstrengungen lösche, schlage ich dasselbe vor und mache etwas Produktiveres. Und akzeptiere Chris 'Bemühungen.
Mico
1

Es ist sehr wahrscheinlich, dass sowohl openweathermap.org als auch www.mocky.io http oder Port 80 unterstützen. Nachfolgend einige Hinweise.

openweathermap.org

Openweathermap

openweathermap-url

www.mocky.io

verspottet

Mocky-URL

Sieht so aus, als würde requestb.in nur HTTPS oder Port 443 unterstützen.

requestb.in

requestb

requestb-url

Dies könnte das Problem erklären. Im Folgenden finden Sie einige Referenzen, die hilfreich sein könnten.

Im CC3100-Datenblatt gibt es keine Verweise auf CC3100, die mit HTTPS arbeiten. Alle Verweise beziehen sich nur auf HTTP. Dies erklärt das Problem wahrscheinlich besser. Fügen Sie unten eine Ausnahme aus dem Datenblatt hinzu.

CC3100 - Datenblatt ausgenommen

Laut Datenblatt unterstützt CC3120 HTTPS. Anhang unten ist außer aus dem Datenblatt. Es gibt nur wenige Verweise auf HTTPS.

CC3100 - Datenblatt ausgenommen

Der wahrscheinlichste Weg nach vorne ist das Ersetzen des CC3100 durch CC3120.

Verweise:

Mahendra Gunawardena
quelle
1
Nach zahlreichen Änderungen, bei denen Fehler eingeführt und anschließend korrigiert wurden, könnte dies nun eine tatsächliche Antwort sein. Aber Sie müssen es wirklich noch umschreiben: Wenn Ihre These lautet, dass eine Site http und die andere nur https unterstützt, dann sagen Sie das einfach im Voraus.
Chris Stratton
2
Und Ihre Analyse des CC3100 und die Ersatzempfehlung bleiben völlig fehlerhaft. Es heißt ausdrücklich, dass es TLS / SSL unterstützt, während Sie versuchen zu argumentieren, dass dies nicht der Fall ist, indem Sie fälschlicherweise die Webserverfähigkeit überprüfen, wenn die Frage nichts damit zu tun hat, ein Server zu sein. Die Frage ist eigentlich, überhaupt keine HTTP-Bibliothek zu verwenden, sondern manuell auf einem TCP-Socket. Um einen HTTPS-Server zu kontaktieren, müssten ähnliche Vorgänge auf einer SSL-Verbindung ausgeführt werden.
Chris Stratton