L'appareil de test IOT MSP430F5529 + CC3100 ne répond qu'à certains sites Web de test

8

Récemment, j'ai travaillé sur un projet IoT utilisant un microcontrôleur MSP430F5529 et un processeur réseau CC3100 tous deux de Texas Instrument. Pour l'évaluation, j'utilise la rampe de lancement MSP430F5529 et le boosterpack CC3100 . J'essaie de faire en sorte que l'appareil se connecte au cloud. J'ai réussi à implémenter l' application d'exemple de météo CC3100 qui se connecte à www.openweathermap.org . Cet exemple provient des exemples d'application du SDK CC3100 . Le programme reçoit et répond avec succès du site Web www.openweathermap.org . L'application utilise la méthode GET pour faire une demande à partir du site Web.

J'ai également testé avec succès le code contre www.mocky.io . L'appareil reçoit une réponse de code d'état 200 OK. Mais lorsque je teste contre le site de test requestb.in , je n'obtiens ni un code de réponse d'erreur 408 Timeout ni un code de réponse de redirection d'URL de 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"*

Ci-dessous est le principal qui comprend certaines des conditions de configuration. Une partie du code de gestion des erreurs a été supprimée par souci de concision.

 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;
}

Ci-dessous se trouve le code getCredentials () qui appelle get data.

<!-- 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;
}

Ci-dessous est une fonction getdata ()j'obtiens l'erreur.

/*!
    \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;
}

La sécurité du point d'accès est configurée comme

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

Enfin, il existe peu de capteurs POC fabriqués avec CC3100 qui doivent transférer des données vers le cloud. Pour plus de simplicité, nous utilisons le boosterpack, nous devons finalement faire en sorte que les capteurs POC communiquent avec le cloud via le Wifi.

user8055
la source
Je vote pour fermer cette question comme hors sujet, car le problème réel concerne la base de l'utilisation HTTP et, dans une moindre mesure, une plate-forme embarquée particulière, pas l'Internet des objets, donc le pool de points communs est avec d'autres questions HTTP d'abord, et pas vraiment à d'autres questions IoT.
Chris Stratton
1
Pour info l'instance spécifique de requestb.in dans votre code a apparemment expiré et maintenant 404 lors de l'accès via HTTP sur TLS avec SNI en tant que travaux pour ceux actuellement valides.
Chris Stratton
@mico, j'ai remarqué que vous avez supprimé votre réponse. Vous avez également mentionné l'ajout d'un "s" à http. Je ne sais pas comment je peux réaliser votre suggestion. Pouvez-vous s'il vous plaît me donner quelques idées.
user8055
@ChrisStratton, Désolé d'entendre que vous votez pour fermer ces questions. Pouvez-vous me recommander un bon site de questions / réponses pour poser cette question?
user8055
Recevez-vous ces messages 302 et 408 ou non? Sinon, quels messages recevez-vous?
mico

Réponses:

5

La différence est que le site requestb.in nécessite HTTP sur TLS avec SNI

Il s'agit d'un protocole HTTP / HTTPS assez complexe et d'une question de sécurité probablement mieux abordée ailleurs dans le système SE, et concernant principalement les détails du requestb.inservice contre lequel vous testez plutôt que le projet IoT que vous pourriez éventuellement faire. Mais tant qu'il reste ici ...


Débogage du code de réponse requestb.in lors d'une tentative de HTTP sur le port 80

Tu as dit:

Mais lorsque je teste contre le site de test requestb.in, je n'obtiens ni un code de réponse d'erreur 408 Timeout ni un code de réponse de redirection d'URL de 302.

Voyons ce qui se passe:

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

Le statut HTTP 301 est "Déplacé en permanence", tandis que le 302 que vous attendiez est parfois utilisé pour une redirection temporaire . Puisqu'ils ne prévoient probablement pas de vous laisser utiliser HTTP sur un socket TCP ordinaire sur le port 80, la redirection permanente qu'ils envoient est la réponse la plus correcte.

Cela aurait été beaucoup plus utile si vous aviez capturé le code d'état que _a été_ envoyé plutôt que d'en répertorier simplement deux qui_n'ont pas été_ envoyés

Quoi qu'il en soit, ce que le serveur dit, c'est que nous devons utiliser HTTPS.


Alors, que devez-vous faire pour vous connecter au serveur via HTTPS?

À un niveau de base, HTTPS signifie simplement parler HTTP sur une connexion sécurisée avec TLS (ou auparavant, SSL), plutôt que de le faire sur un socket TCP ordinaire.

Votre CC3100 prend en charge TLS et SSL , et il existe quelques informations minimales sur la modification de l'un des exemples de client HTTP du SDK pour effectuer une connexion HTTPS en créant à la place un canal sécurisé, disponible sur http://processors.wiki.ti.com/index.php / CC3100_HTTP_Client

Cependant, dans ce cas, requestb.incela pourrait ne pas être suffisant.

Si vous s_clientdeviez envoyer une requête GET très simple dans la commande openssl (ou faire la même chose sur le CC3100)

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

(le sleepfait de faire ouvrir à openssl une réponse plutôt que de raccrocher à la fin de l'entrée)

Vous obtiendriez une erreur étrange:

Routines SSL: SSL23_GET_SERVER_HELLO: échec de la négociation de l'alerte sslv3

Vous pourriez penser que cela a quelque chose à voir avec les versions SSL vs TLS, mais en fait c'est parce que cela requestb.innécessite quelque chose appelé Server Name Indication (Wikipedia) . Cela signifie que vous devez indiquer à la pile SSL d'indiquer au serveur sous quel nom de serveur il doit s'authentifier.

En poursuivant avec les démonstrations en ligne de commande, nous ajoutons simplement un -servernameargument:

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

Si cela est fait avec le hachage URL d'une instance requestb.in valide, cela produit un résultat et est visible dans le panneau de journalisation du navigateur qui l'a créé.


Implémentation de l'indication de nom de serveur (SNI) sur le CC3xxx

Il y a des messages sur le forum suggérant que l'implémentation TLS sur le CC3xxx n'a pas supporté SNI, et qu'il n'y a pas de plans concrets pour l'ajouter; cependant, vous pouvez vérifier si c'est toujours le cas.

Mais il est important de se rappeler qu'il y a un arbre de couches réseau impliqué:

WiFi
  IP packets
    TCP session
      TLS session
        HTTP protocol

Étant donné que le CC3100 vous permet de parler TCP (et en fait, vous le faisiez dans votre code existant), vous êtes libre d'apporter "votre propre" implémentation TLS qui prend en charge SNI. Par exemple, ce billet de blog traite du portage de la bibliothèque mbed TLS (anciennement PolarSSL) vers le CC3xxx et mentionne SNI comme capacité.

TL; DR

requestb.inest une cible difficile car elle nécessite que vous parliez HTTP sur une session sécurisée avec TLS et implémentant l' indication de nom de serveur . Si parler à cet hôte ne fait pas partie de votre projet ultime, il pourrait être préférable de simplement passer aux hôtes qui sont - ceux destinés à être utilisés avec un minimum de clients intégrés sur les appareils IoT pourraient bien être configurés pour rendre les choses un peu plus faciles en n'utilise pas SNI.

Il sera également beaucoup plus efficace si vous prenez l'habitude de capturer les détails des problèmes que vous rencontrez - le développement intégré est toujours difficile à déboguer, et moins il y a d'informations sur les échecs que vous capturez via la journalisation ou un débogueur, plus vous passez de temps à deviner .

Chris Stratton
la source
Semble une bonne réponse, mais est au-delà de ma compréhension. J'espère atteindre ce niveau de connaissances approfondies dans un avenir proche. Mais merci beaucoup pour la réponse.
user8055
1
L'exigence SNI le rend en effet compliqué - ma recommandation serait d'ignorer requestb.in, de se concentrer sur les exigences de tout ce à quoi vous essayez de parler dans votre projet réel et, si nécessaire, de trouver un service de simulation qui ressemble plus à cette exigence.
Chris Stratton
Maintenant, en lisant ceci et après avoir supprimé deux de mes efforts concurrentiels, je suggère la même chose, faites quelque chose de plus productif. Et acceptez les efforts de Chris.
mico
1

Il est très probable que openweathermap.org et www.mocky.io prennent en charge http ou le port 80. Ci-dessous, quelques indices.

openweathermap.org

Openweathermap

openweathermap-url

www.mocky.io

moqueur

mocky-url

On dirait que requestb.in prend en charge HTTPS ou le port 443 uniquement.

requestb.in

requestb

requestb-url

Cela pourrait expliquer le problème. Voici quelques références qui pourraient vous aider.

Dans la fiche technique du CC3100, il n'y a aucune référence au CC3100 fonctionnant avec HTTPS. Toutes les références concernent uniquement HTTP. Cela explique probablement mieux le problème. Attachez ci-dessous un sauf de la fiche technique.

CC3100 - Exceptions de la fiche technique

Ressemble à la fiche technique CC3120 prend en charge HTTPS. Attacher ci-dessous est sauf de la fiche technique. Il y a peu de références à HTTPS.

CC3100 - Exceptions de la fiche technique

La voie à suivre la plus probable est de remplacer le CC3100 par le CC3120.

Références:

Mahendra Gunawardena
la source
1
Après de nombreuses modifications introduisant des erreurs, puis les corrigeant, cela pourrait maintenant devenir une véritable réponse. Mais vous avez vraiment encore besoin de le réécrire: si votre thèse est qu'un site prend en charge http et l'autre uniquement https, alors dites-le tout de suite.
Chris Stratton
2
Et votre analyse du CC3100 et de la recommandation de remplacement reste entièrement erronée. Il dit explicitement qu'il prend en charge TLS / SSL, tandis que vous essayez de faire valoir qu'il ne le fait pas en regardant par erreur sa capacité de serveur Web, lorsque la question n'a rien à voir avec le fait d'être un serveur. La question n'est pas du tout d'utiliser une bibliothèque HTTP, mais de le faire manuellement sur un socket TCP. Pour contacter un serveur HTTPS, il devrait effectuer des opérations similaires sur une connexion SSL.
Chris Stratton