MSP430F5529 + CC3100 IOT test device only responds to some test websites

user8055
  • MSP430F5529 + CC3100 IOT test device only responds to some test websites user8055

    Recently I have been working on an IoT project using a MSP430F5529 microcontroller and CC3100 network processor both from Texas Instrument. For evaluation I am using the MSP430F5529 launch pad and CC3100 boosterpack. I am trying to get the device to connect to the cloud. I have successfully implement the CC3100 get weather example application which connects to www.openweathermap.org. This is example is from CC3100 SDK Sample Applications. The program successfully receives and response back from the www.openweathermap.org website. The application uses the GET method make a request from the website.

    I have also have successfully tested the code against www.mocky.io. The device receives a status code 200 OK response. But when I test against requestb.in test site I don’t get either a 408 Timeout error response code or a URL redirection response code of 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"*
    

    Below is the main which includes some of setup conditions. Some of the error handling code has been removed for brevity.

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

    Below is getCredentials() code which calls 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;
    }
    

    Below is a getdata() function where I am getting the error.

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

    The security for the access point is setup as

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

    Finally there are few POC sensor devices fabricated with CC3100 that need to transfer data to the cloud. For simplicity we are using the boosterpack, eventually we need to get the POC sensor devices communicating to cloud via Wifi.

  • It is highly likely that both openweathermap.org and www.mocky.io support http or port 80. Below are few clues.

    openweathermap.org

    Openweathermap

    openweathermap-url

    www.mocky.io

    mocky

    mocky-url

    Looks like requestb.in support HTTPS or port 443 only.

    requestb.in

    requestb

    requestb-url

    This might explain the issue. Below are few references that might help.

    In the CC3100 datasheet there are no references to CC3100 working with HTTPS. All references are to HTTP only. This probably better explains the issue. Attach below an except from the datasheet.

    CC3100 - Datasheet excepts

    Looks like per datasheet CC3120 supports HTTPS. Attach below is except from the datasheet. There are few references to HTTPS.

    CC3100 - Datasheet excepts

    The most likely path forward is replace the CC3100 with CC3120.

    References:

  • The difference is because the requestb.in site requires HTTP over TLS with SNI

    This is a fairly complex HTTP/HTTPS protocols and security question likely better addressed elsewhere in the SE system, and mostly concerning details of the requestb.in service you are testing against rather than whatever IoT project you might eventually be doing. But so long as it remains here...


    Debugging the requestb.in response code when attempting HTTP on port 80

    You said:

    But when I test against requestb.in test site I don’t get either a 408 Timeout error response code or a URL redirection response code of 302.

    Let's see what happens:

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

    HTTP status 301 is "Moved Permanently", while the 302 you were expecting is sometimes used for a temporary redirect. Since they're probably not planning to ever let you use HTTP on a plain TCP socket on port 80, the permanent redirect they send is the more correct response.

    It would have been a lot more helpful if you had captured the status code which _was_ sent rather than merely listing two which _were not_ sent

    At any rate, what the server is telling is that we must use HTTPS.


    So what would you need to do to connect to the server via HTTPS?

    At a basic level, HTTPS simply means speaking HTTP over a connection secured with TLS (or previously, SSL), rather than doing so over a plain TCP socket.

    Your CC3100 supports TLS and SSL, and there's some minimal information about modifying one of the SDK's HTTP client examples to perform an HTTPS connection by instead making a secure channel, available at http://processors.wiki.ti.com/index.php/CC3100_HTTP_Client

    However, in the case of requestb.in this may well not be sufficient.

    If you were to pipe a very simple GET request into openssl's s_client command (or do the same thing on the CC3100)

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

    (the sleep is to make openssl wait for a response rather than hangup at the conclusion of the input)

    You'd get an odd error:

    SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure

    You might thing this has something to do with SSL vs. TLS versions, but actually it's because requestb.in requires something called Server Name Indication (Wikipedia). This effectively means you need to tell the SSL stack to tell the server which servername it should authenticate as.

    Continuing with the command line demonstrations, we'd simply add a -servername argument:

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

    If this is done with the URL hash of a valid requestb.in instance, it produces a result and is visible in the log panel of the browser which created that.


    Implementing Server Name Indication (SNI) on the CC3xxx

    There are some forum posts suggesting that the TLS implementation on the CC3xxx has not supported SNI, and that there aren't concrete plans to add this; however, you could verify if that is still the case.

    But it's important to remember that there's a tree of network layers involved:

    WiFi
      IP packets
        TCP session
          TLS session
            HTTP protocol
    

    Since the CC3100 allows you to speak TCP (and in fact you were doing so in your existing code), you're free to "bring your own" TLS implementation that does have SNI support. For example, this blog post discusses porting the mbed TLS (formerly PolarSSL) libary to the CC3xxx and mentions SNI as capability.

    TL;DR

    requestb.in is a challenging target as it requires that you speak HTTP over a session secured with TLS and implementing Server Name Indication. If talking to this host isn't part of your ultimate project you might find it better to simply move on to those hosts which are - those intended for use with minimal embedded clients on IoT devices might well be configured to make things a bit easier by not using SNI.

    It's also going to be far more efficient if you get in the habit of capturing the details of problems you encounter - embedded development is always challenging to debug, and the less information about failures you capture via logging or a debugger, the more time spent guessing.

Tags
microcontrollers wifi
Related questions and answers
  • which calls get data. &lt;!-- language: lang-c --> static _i32 getCredentials() { _i32 retVal = -1; pal_Strcpy((char *)g_DeviceData.HostName, TEST_SERVER); retVal = getHostIP_Device... and CC3100 boosterpack. I am trying to get the device to connect to the cloud. I have successfully implement the CC3100 get weather example application which connects to www.openweathermap.org.... the website. I have also have successfully tested the code against www.mocky.io. The device receives a status code 200 OK response. But when I test against requestb.in test site I don’t get either a 408

  • *data, unsigned int count) { char *c = (char *)data; for (unsigned int i = 0; i &lt; count; i++) { USART_Tx(USART0, c[i]); } return count; } void main(void) { #ifdef...); } /** @} (end addtogroup I2C) */ /** @} (end addtogroup emlib) */ #endif /* defined(I2C_COUNT) &amp;&amp; (I2C_COUNT > 0) */ Here are some relevant links: The data sheet for the microcontroller I am using..._TypeDef seq; seq.addr = 0x90; seq.flags = 0x0001; seq.buf[0].data[0] = 0x00; seq.buf[0].len = 1; seq.buf[1].data[0] = 0x01; seq.buf[1].len = 1; printf("Attempting to start transfer\n\r

  • *data, unsigned int count) { char *c = (char *)data; for (unsigned int i = 0; i &lt; count; i++) { USART_Tx(USART0, c[i]); } return count; } void main(void) { #ifdef...); } /** @} (end addtogroup I2C) */ /** @} (end addtogroup emlib) */ #endif /* defined(I2C_COUNT) &amp;&amp; (I2C_COUNT > 0) */ Here are some relevant links: The data sheet for the microcontroller I am using..._TypeDef seq; seq.addr = 0x90; seq.flags = 0x0001; seq.buf[0].data[0] = 0x00; seq.buf[0].len = 1; seq.buf[1].data[0] = 0x01; seq.buf[1].len = 1; printf("Attempting to start transfer\n\r

  • to be hitting the server. I'm new in this area, how to start investigating? How to debug? Code (note the wifi_event_group lines are commented out due to causing different error...): #include &lt..._event_group, WIFI_CONNECTED_BIT); wifi_connected = 0; break; default: break; } return ESP_OK; } static void mg_ev_handler(struct mg_connection *nc, int ev, void *ev_data..., &amp;write_set, &amp;err_set, &amp;timeout) == 1) { n = read(0, msg, sizeof(msg)); } if (n &lt;= 0) break; while (msg[n - 1] == '\r' || msg[n - 1] == '\n') n

  • to be hitting the server. I'm new in this area, how to start investigating? How to debug? Code (note the wifi_event_group lines are commented out due to causing different error...): #include &lt..._event_group, WIFI_CONNECTED_BIT); wifi_connected = 0; break; default: break; } return ESP_OK; } static void mg_ev_handler(struct mg_connection *nc, int ev, void *ev_data..., &amp;write_set, &amp;err_set, &amp;timeout) == 1) { n = read(0, msg, sizeof(msg)); } if (n &lt;= 0) break; while (msg[n - 1] == '\r' || msg[n - 1] == '\n') n

  • : "); String messageTemp; for (int i = 0; i &lt; length; i++) { Serial.print((char)message[i]); messageTemp += (char)message[i]; } Serial.println(); if(topic=="esp8266/2.... Mosquitto is running fine. For now, what I am trying to do is trigger a relay wired up with esp8266 (GPIO2). Here is my Python web server code: import paho.mqtt.client as mqtt from flask import Flask... } @app.route("/") def main(): # Pass the template data into the template main.html and return it to the user return render_template('main.html', **templateData) # The function below is executed when

  • : "); String messageTemp; for (int i = 0; i &lt; length; i++) { Serial.print((char)message[i]); messageTemp += (char)message[i]; } Serial.println(); if(topic=="esp8266/2.... Mosquitto is running fine. For now, what I am trying to do is trigger a relay wired up with esp8266 (GPIO2). Here is my Python web server code: import paho.mqtt.client as mqtt from flask import Flask... } @app.route("/") def main(): # Pass the template data into the template main.html and return it to the user return render_template('main.html', **templateData) # The function below is executed when

  • (); PN532_StartScan(); } But surprisingly, for the below code, the card is detected, the write works, but when next the read happens after the card is detected, I get a status error response as 0x27 which... proximity. I have ported the necessary functions from the Adafruits library here for the ATxmega32A4U. To scan and read an NTAG213 card, I am using the below functions. // Reads cards, beep and long... */ PORTA.INT1MASK &amp;= ~(1&lt;&lt;PIN7_bp); /* Send scan command and read acknowledgments */ if (PN532_writeCommand(pn532_packetbuffer, 3, NULL, 0)) ret = 0x0; // command failed

  • (); PN532_StartScan(); } But surprisingly, for the below code, the card is detected, the write works, but when next the read happens after the card is detected, I get a status error response as 0x27 which... proximity. I have ported the necessary functions from the Adafruits library here for the ATxmega32A4U. To scan and read an NTAG213 card, I am using the below functions. // Reads cards, beep and long... */ PORTA.INT1MASK &amp;= ~(1&lt;&lt;PIN7_bp); /* Send scan command and read acknowledgments */ if (PN532_writeCommand(pn532_packetbuffer, 3, NULL, 0)) ret = 0x0; // command failed

Data information