httpbin_org crashes on CYW943907AEVAL1F Eval. Brd

Tip / Sign in to post questions, reply, level up, and achieve exciting badges. Know more

cross mob
ChMa_3922746
Level 5
Level 5
10 likes received 10 likes given 5 likes given

I need the CYW943907AEVAL1F to connect to an external HTTPS web server and retrieve the contents.  I used snip/httpbin_org as a starting point as it looked like it provided what I need.

When the application is run "as is", things works fine.  However, when I modify the application to run more than once, the board reboots at this point:

if ( ( result = http_client_connect( &client, (const wiced_ip_address_t*)&ip_address, SERVER_PORT, HTTP_USE_TLS, CONNECT_TIMEOUT_MS ) ) != WICED_SUCCESS )

Apparently, the function http_client_connect does not like being called twice.  This would be a problem as I need this function to be called again and again.

Has this been observed by anyone before?

Thanks!

0 Likes
1 Solution

I discovered the NetX_Duo_User_Guide which was very helpful (it is located in the directory /43xxx_Wi-Fi/WICED/network/NetX_Duo/ver5.10_sp3/docs).

I isolated the failure to the function nxd_tcp_client_socket_connect in this file:  /43xxx_Wi-Fi/WICED/network/NetX_Duo/WICED/tcpip.c

It was returning 0x35 which, according to the document, meant "NX_NOT_CLOSED:  Socket is not in a closed state".

Therefore, before the call to the nxd_tcp_client_socket_connect function, I added this line to ensure the socket is put into a closed state:

nx_tcp_socket_disconnect(&socket->socket, NX_TIMEOUT(timeout_ms) );

That is the only change required.  Now I can call http_client_connect at any time.  This solution works both for HTTP over port 80 and HTTPS over port 443 (with TLS).

I would recommend that this change be made in the WICED SDK.

----------------------------------------------------------------------------

(PS:  The code now looks like so:

...

/* Check if socket is not yet bound to a local port */

    if ( !socket->socket.nx_tcp_socket_bound_next )

    {

        net_result = nx_tcp_client_socket_bind( &socket->socket, NX_ANY_PORT, NX_TIMEOUT(WICED_TCP_BIND_TIMEOUT) );

        if ( net_result != NX_SUCCESS )

        {

            return netx_returns[net_result];

        }

    }

    // Need to add "nx_tcp_socket_disconnect" to put socket in CLOSED state

   nx_tcp_socket_disconnect(&socket->socket, NX_TIMEOUT(timeout_ms) );

    net_result = nxd_tcp_client_socket_connect( &socket->socket, (NXD_ADDRESS*) address, port, NX_TIMEOUT(timeout_ms) );

...

)

View solution in original post

0 Likes
9 Replies
ChMa_3922746
Level 5
Level 5
10 likes received 10 likes given 5 likes given

I did a bit of rejigging so that the initial construction of the client connection takes place only once.  Then I can create consecutive requests that succeed.  However, after a period of time, the connection times out. Then, if I call http_client_connect again (same line as stated above), the system crashes and reboots:

if ( ( result = http_client_connect( &client, (const wiced_ip_address_t*)&ip_address, SERVER_PORT, HTTP_USE_TLS, CONNECT_TIMEOUT_MS ) ) != WICED_SUCCESS )

It seems that this function cannot be called more than once?

0 Likes

Each HTTP connection involves TCP socket connection as well as series of TLS handshakes which would consume time and memory. Each HTTP connect should be balanced by HTTP disconnect. While looping requests, it is better to use semaphore or mutex which would ensure that each request is atomic.

Please refer to the following threads for some more information:

HTTP Connection stuck

multiple HTTP post request threads

Thank you, that is helpful.  My test connects to the website httpbin.org (per the example).  I now use a mutex so that the event_handler function allows my application to determine whether the connection has been disconnected.

1) Based upon your advice, I now call the following only at the start:

wiced_tls_init_root_ca_certificates(...)

http_client_init(...)

http_client_configure(...)

2) Then, I can call the following as many times as I want in quick succession and each results in a good GET:

http_client_connect(...)

http_request_init(...)

http_request_write_header(...)

http_request_flush(...)

3) After httpbin.org disconnects automatically, then repeating the call to http_client_connect(...) alone always fails (Error: failed to connect client to server: 4, which is caused by the failure of the function wiced_tcp_connect in tcpip.c).

I actually need to repeat the entire sequence of Step 2 one or two times before it connects and I get a good GET.  Then, things are fine until it disconnects again in which case I need to repeat Step 2 (and so on).

This behaviour is odd/a bit broken, though somewhat functional.

0 Likes

After a disconnection, it seems that I need to run http_request_init and http_request_deinit after the connect function a few times in order for it to connect to httpbin.org again.  As it turns out, after the loop runs 7 times, then it connects.

a = 0;

// loop until connection is made

while ( (http_client_connect( &client, (const wiced_ip_address_t*)&ip_address, HTTPS_SERVER_PORT, HTTP_USE_TLS, CONNECT_TIMEOUT_MS  != WICED_SUCCESS) && (a < 10) )

{

    http_request_init( &requests[1], &client, HTTP_GET, request_uris[1], HTTP_1_1 );

    http_request_deinit( &requests[1] );

    ++a;

}

I wonder if it is timing issue (perhaps http_client_connect is returning prematurely).  Quite a mystery.

0 Likes

The http_client_connect() as stated earlier involves TLS handshakes and consumes time. It would be better to call http_client_connect() once and then loop the requests multiple times. Check if "Connection: keep-alive" header solves the issue of automatic disconnection.

If I call http_client_connect() only once, then, yes:  It does work well until the remote server disconnects.  Note that I do send the "Connection: keep-alive" in the header.  But the website times-out after about a minute or so, anyway.

There must be a way to start a new connection after a disconnect... I just have no idea how to do that reliably.  (Note that my strategy of looping, above, does cause a reboot eventually which indicates that some memory is being used up, or a pointer is going astray.)

I tried regular HTTP (TLS off), and the results are the same.

I wonder what other designers have done...?

0 Likes

Putting http_client_connect() in a while loop is likely to cause reboot due to large memory consumption during TLS handshakes. There is nothing on the WICED application side that should cause a timed HTTP disconnect. If there is a disconnection, it should pass through the HTTP_DISCONNECTED event. In that event, in addition to http_request_deinit(), the http_client_disconnect() could be called to ensure that memory is deallocated. You can set a flag in this event which could be checked in the main loop to re-establish connection. Basically just ensure that there is a balance between memory allocation and deallocation in your code. There has been some prior discussion on this issue https://community.cypress.com/thread/33941 but it stopped at calling http_client_connect() once but that is not your requirement.

Thank you so much for your continued help.  You are right:  It is not WICED that is disconnecting, but the website.  I did try this, but the http_client_disconnect causes a crash/reboot:

static void event_handler( http_client_t* client, http_event_t event, http_response_t* response )

{

...

case HTTP_DISCONNECTED:

        {

            WPRINT_APP_INFO(( "Disconnected from %s\n", SERVER_HOST ));

            http_request_deinit( &requests[1] );

            http_client_disconnect( &client );

            // get mutex and change client_is_connected state to false (I added this)

            wiced_rtos_lock_mutex( &client_status.mutex );

            client_status.client_connected = WICED_FALSE;

            wiced_rtos_unlock_mutex( &client_status.mutex );

            break;

        }

...

}

I had tried that early on, but due to the reboot, I thought the HTTP_DISCONNECTED event would have already de-allocated the memory.

Note that the same failure happens with plain HTTP (without TLS enabled), so it's not due to TLS handshaking.

There must be a way to figure out what is going on here...

0 Likes

I discovered the NetX_Duo_User_Guide which was very helpful (it is located in the directory /43xxx_Wi-Fi/WICED/network/NetX_Duo/ver5.10_sp3/docs).

I isolated the failure to the function nxd_tcp_client_socket_connect in this file:  /43xxx_Wi-Fi/WICED/network/NetX_Duo/WICED/tcpip.c

It was returning 0x35 which, according to the document, meant "NX_NOT_CLOSED:  Socket is not in a closed state".

Therefore, before the call to the nxd_tcp_client_socket_connect function, I added this line to ensure the socket is put into a closed state:

nx_tcp_socket_disconnect(&socket->socket, NX_TIMEOUT(timeout_ms) );

That is the only change required.  Now I can call http_client_connect at any time.  This solution works both for HTTP over port 80 and HTTPS over port 443 (with TLS).

I would recommend that this change be made in the WICED SDK.

----------------------------------------------------------------------------

(PS:  The code now looks like so:

...

/* Check if socket is not yet bound to a local port */

    if ( !socket->socket.nx_tcp_socket_bound_next )

    {

        net_result = nx_tcp_client_socket_bind( &socket->socket, NX_ANY_PORT, NX_TIMEOUT(WICED_TCP_BIND_TIMEOUT) );

        if ( net_result != NX_SUCCESS )

        {

            return netx_returns[net_result];

        }

    }

    // Need to add "nx_tcp_socket_disconnect" to put socket in CLOSED state

   nx_tcp_socket_disconnect(&socket->socket, NX_TIMEOUT(timeout_ms) );

    net_result = nxd_tcp_client_socket_connect( &socket->socket, (NXD_ADDRESS*) address, port, NX_TIMEOUT(timeout_ms) );

...

)

0 Likes