O dispositivo de teste IOT MSP430F5529 + CC3100 responde apenas a alguns sites de teste

8

Recentemente, tenho trabalhado em um projeto de IoT usando um microcontrolador MSP430F5529 e um processador de rede CC3100, ambos da Texas Instrument. Para avaliação, estou usando a plataforma de lançamento MSP430F5529 e o boosterpack CC3100 . Estou tentando fazer com que o dispositivo se conecte à nuvem. Eu implementei com sucesso o aplicativo de exemplo climático CC3100 , que se conecta a www.openweathermap.org . Este é o exemplo dos aplicativos de amostra do CC3100 SDK . O programa recebe e responde com sucesso do site www.openweathermap.org . O aplicativo usa o método GET para fazer uma solicitação no site.

Também testei o código com sucesso em www.mocky.io . O dispositivo recebe uma resposta OK do código de status 200. Mas quando testo no site de teste requestb.in , não recebo um código de resposta de erro 408 Timeout ou um código de resposta de redirecionamento de URL 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"*

Abaixo está o principal, que inclui algumas condições de configuração. Alguns dos códigos de manipulação de erros foram removidos por questões de brevidade.

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

Abaixo está o código getCredentials () que chama obter dados.

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

Abaixo está uma função getdata () onde estou recebendo o erro.

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

A segurança do ponto de acesso é configurada como

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

Finalmente, existem poucos dispositivos sensores POC fabricados com o CC3100 que precisam transferir dados para a nuvem. Para simplificar o uso do boosterpack, eventualmente precisamos que os dispositivos do sensor POC se comuniquem com a nuvem via Wifi.

user8055
fonte
Estou votando para encerrar esta questão como fora de tópico, porque o problema real da pergunta é sobre o uso básico de HTTP e, em menor grau, uma plataforma incorporada específica, não a Internet das Coisas; portanto, o conjunto de informações comuns é sobre outras questões de HTTP primeiro, e não realmente para outras perguntas de IoT.
22617 Chris Stratton
1
Para sua informação, a instância requestb.in específica em seu código aparentemente atingiu o tempo limite e agora é 404 quando acessada via HTTP através de TLS com SNI, como funciona para as atualmente válidas.
22717 Chris Stratton
@mico, notei que você removeu sua resposta. Você também mencionou adicionar um "s" ao http. Não tenho certeza de como conseguir sua sugestão. Você pode me dar algumas idéias?
user8055
@ ChrisStratton, desculpe ouvir que você está votando para encerrar essas perguntas. Você pode me recomendar um bom site de perguntas e respostas para fazer esta pergunta?
user8055
Você recebe essas mensagens 302 e 408 ou não? Caso contrário, que mensagens você recebe?
Mico

Respostas:

5

A diferença é que o site requestb.in requer HTTP sobre TLS com SNI

Essa é uma questão bastante complexa sobre protocolos HTTP / HTTPS e segurança, provavelmente melhor abordada em outras partes do sistema SE, e principalmente sobre detalhes do requestb.inserviço em que você está testando, em vez de qualquer projeto de IoT que você possa estar fazendo. Mas enquanto ele permanecer aqui ...


Depurando o código de resposta requestb.in ao tentar HTTP na porta 80

Você disse:

Mas quando testo no site de teste requestb.in, não recebo um código de resposta de erro 408 Timeout ou um código de resposta de redirecionamento de URL 302.

Vamos ver o que acontece:

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

O status HTTP 301 é "Movido permanentemente", enquanto o 302 que você esperava às vezes é usado para um redirecionamento temporário . Como eles provavelmente não estão planejando permitir que você use HTTP em um soquete TCP simples na porta 80, o redirecionamento permanente que eles enviam é a resposta mais correta.

Seria muito mais útil se você capturasse o código de status que foi enviado em vez de apenas listar dois que não foram enviados

De qualquer forma, o que o servidor está dizendo é que devemos usar HTTPS.


Então, o que você precisaria fazer para se conectar ao servidor via HTTPS?

Em um nível básico, HTTPS significa simplesmente falar HTTP através de uma conexão protegida com TLS (ou anteriormente, SSL), em vez de fazê-lo através de um soquete TCP simples.

Seu CC3100 suporta TLS e SSL , e há algumas informações mínimas sobre como modificar um dos exemplos de cliente HTTP do SDK para executar uma conexão HTTPS, criando um canal seguro, disponível em http://processors.wiki.ti.com/index.php / CC3100_HTTP_Client

No entanto, nesse caso, requestb.inpode não ser suficiente.

Se você canalizar uma solicitação GET muito simples no s_clientcomando openssl (ou faça a mesma coisa no CC3100)

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

( sleepé fazer com que o openssl aguarde uma resposta em vez de interromper a conclusão da entrada)

Você receberá um erro estranho:

Rotinas SSL: SSL23_GET_SERVER_HELLO: falha do handshake de alerta sslv3

Você pode pensar que isso tem algo a ver com versões SSL vs. TLS, mas na verdade é porque requestb.inrequer algo chamado Indicação de Nome de Servidor (Wikipedia) . Isso significa efetivamente que você precisa informar à pilha SSL para informar ao servidor qual nome do servidor deve ser autenticado.

Continuando com as demonstrações da linha de comando, simplesmente adicionamos um -servernameargumento:

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

Se isso for feito com o hash da URL de uma instância requestb.in válida, ele produzirá um resultado e ficará visível no painel de log do navegador que o criou.


Implementando a Indicação do Nome do Servidor (SNI) no CC3xxx

Existem algumas postagens no fórum sugerindo que a implementação do TLS no CC3xxx não oferece suporte ao SNI e que não há planos concretos para adicionar isso; no entanto, você pode verificar se esse ainda é o caso.

Mas é importante lembrar que há uma árvore de camadas de rede envolvidas:

WiFi
  IP packets
    TCP session
      TLS session
        HTTP protocol

Como o CC3100 permite que você fale TCP (e na verdade estava fazendo isso no seu código existente), você pode "trazer o seu próprio" implementação de TLS que possui suporte SNI. Por exemplo, esta postagem do blog discute como portar a biblioteca TLS mbed (anteriormente PolarSSL) para o CC3xxx e menciona o SNI como recurso.

TL; DR

requestb.iné um destino desafiador, pois exige que você fale HTTP em uma sessão protegida com TLS e que implemente a Indicação do nome do servidor . Se conversar com esse host não fizer parte do seu projeto final, talvez seja melhor simplesmente passar para os hosts que são - aqueles destinados ao uso com o mínimo de clientes incorporados em dispositivos IoT, podem ser configurados para facilitar um pouco as coisas. não usando SNI.

Também será muito mais eficiente se você adquirir o hábito de capturar os detalhes dos problemas que encontrar - o desenvolvimento incorporado é sempre um desafio para depurar, e quanto menos informações sobre falhas capturadas por meio de log ou depurador, mais tempo será adivinhado. .

Chris Stratton
fonte
Parece uma boa resposta, mas está além da minha compreensão. Espero alcançar este nível de conhecimento aprofundado no futuro próximo. Mas muito obrigado pela resposta.
user8055
1
O requisito do SNI realmente torna isso complicado - minha recomendação seria ignorar requestb.in, concentrar-se nos requisitos do que você realmente está tentando conversar em seu projeto real e, se necessário, encontrar um serviço de simulação que seja mais parecido com esse requisito.
22817 Chris Stratton
Agora, ao ler isso e depois de excluir dois dos meus esforços competitivos, sugiro o mesmo, faça algo mais produtivo. E aceite o esforço de Chris.
Mico
1

É altamente provável que o openweathermap.org e o www.mocky.io ofereçam suporte à http ou porta 80. Abaixo estão algumas dicas.

openweathermap.org

Openweathermap

openweathermap-url

www.mocky.io

zombeteiro

mocky-url

Parece que requestb.in suporta apenas HTTPS ou porta 443.

requestb.in

requestb

requestb-url

Isso pode explicar o problema. Abaixo estão algumas referências que podem ajudar.

Na folha de dados do CC3100, não há referências ao CC3100 trabalhando com HTTPS. Todas as referências são apenas para HTTP. Isso provavelmente explica melhor o problema. Anexe abaixo um exceto da folha de dados.

CC3100 - Folha de dados excede

Parece que por folha de dados o CC3120 suporta HTTPS. O anexo abaixo é exceto da folha de dados. Existem poucas referências ao HTTPS.

CC3100 - Folha de dados excede

O caminho mais provável a seguir é substituir o CC3100 pelo CC3120.

Referências:

Mahendra Gunawardena
fonte
1
Depois de inúmeras edições, introduzindo erros e corrigindo-os, isso pode estar se aproximando agora como uma resposta real. Mas você realmente ainda precisa reescrevê-lo: se sua tese é que um site oferece suporte a http e o outro apenas https, basta dizer isso com antecedência.
22617 Chris Stratton
2
E sua análise do CC3100 e recomendação de substituição permanece totalmente incorreta. Ele diz explicitamente que suporta TLS / SSL, enquanto você tenta argumentar que isso não ocorre, olhando erroneamente para a capacidade do servidor da Web, quando a questão não tem nada a ver com ser um servidor. A questão é realmente não usar uma biblioteca HTTP, mas fazê-lo manualmente no topo de um soquete TCP. Para entrar em contato com um servidor HTTPS, seria necessário executar operações semelhantes em uma conexão SSL.
22717 Chris Stratton