TCP / IP Socket Client Issue (RTCS bug?)

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

TCP / IP Socket Client Issue (RTCS bug?)

5,285 Views
rick101
Contributor III

TCP / IP Socket Client Issue (RTCS bug?)

I’m currently using MQX 3.8.1 and Code Warrior 10.3. I’ve written a TCP client to read a web page.

The client is based on the syntax from Freescale’s twitter example. I believe it s correct?, the code works okay when complied on a PC, so it seem like a bug in RTCS?.

Can some please test the following or any other help would be very useful

The Issue

The client connects to targets server but fails to receive a web page from another web server apart from MQX’s own (same board or difference board to the client).

Setup

I’ve based my test setup on MQX’s freescale web server example (\rtcs\examples\httpsrv). I’ve modified only one file (httpdsrv.c). The modification creates a test http client task after the web server is up and running, this then grabs one web page.  It’s very simple, I’ve attached the code, you can copy this file into Freescale’s demo and it should just compile and run.

Working setup terminal out looks like i.e. grabbing an image from its own web server

preparing http server...

run http server...

Http Task Running

Socket Created 35440

Socket Bind Completed 0

Connected to 172.18.11.11, port 80.

Command send to server:-

GET /rtc.html HTTP/1.0

Host: 172.18.11.11

"Response from server - comment added by me"

HTTP/1.0 200 OK

Server: MQX HTTP - Freescale Embedded Web Server

Connection: close

Content-Type: text/html

 

"Web Page being received - comment added by me"

<!DOCTYPE HTML SYSTEM>

<html>

<head>

Etc

Non working terminal output looks like i.e. connect to a non MQX web server

Connected to 172.18.11.53, port 80.

Command send to server:- GET /fs/about.htm HTTP/1.0

Host: 172.18.11.53

HTTP/1.1

Packet received of 9 Bytes Total Bytes Received 9

I do not get a complete HTTP response i.e. 200 / OK,  Server:  etc and no web page, it just hangs at this point

Main body of code is as follows (very much like the twitter example with some minor corrections): -

int_32 httpClient()

{

    uint_32 sockfd = 0;

    uint_32 sent = 0;

    uint_32 numBytes = 0;

    uint_32 loop=0;

    int_32  tmpres;

    uint_32 errCode;

    uint_32 result;

    uint_32 status;

    uint_32 opt_val1 = 10000;

    uint_32 opt_len1 = sizeof(int_32);

    struct sockaddr_in  client;

    /* create socket */

    sockfd = socket(AF_INET, SOCK_STREAM, 0 );

    if ( sockfd == RTCS_SOCKET_ERROR )

    {

        printf("httpClient() - error creating socket %d\n",sockfd);

        return ERROR;

    }

    printf("Socket Created %d\n",sockfd);

    /* added socket options - time out after */

    status = setsockopt(sockfd, SOL_TCP, OPT_RECEIVE_TIMEOUT, &opt_val1, opt_len1);

    if (status != RTCS_OK)

    {

        printf("\n[TCPClient]: Failed to setsockopt for OPT_RECEIVE_TIMEOUT = 0x%x.", status);

        shutdown (sockfd,FLAG_ABORT_CONNECTION);

        return ERROR;

    }

    /* bind socket */

    client.sin_family      = AF_INET;

    client.sin_addr.s_addr = INADDR_ANY;

    client.sin_port        = TCP_CLIENT_PORT;   

    result = bind(sockfd, &client, sizeof(client));

    if ( result != RTCS_OK )

    {

        printf("\nError, bind() failed with error code %lx", result);

        shutdown(sockfd, FLAG_CLOSE_TX);

        return ERROR;

    }

    printf("Socket Bind Completed %d\n",result);

    /* set socket port and address */

    client.sin_port = HTTP_PORT;                                     /* htons not used in MQX */

    client.sin_addr.s_addr = IPADDR(CAADD1, CAADD2, CAADD3, CAADD4); /* MQX specfic macro     */

    client.sin_family = AF_INET;

    result = connect(sockfd, &client, sizeof(client));

    if (result != RTCS_OK)

    {

        printf("\nError--connect() failed with error code %lx.\n",result);

    }

    else

    {

        printf("\nConnected to %d.%d.%d.%d, port %d.\n",IPBYTES(client.sin_addr.s_addr), client.sin_port);

    }

    /* send command to the server */

    tmpres = send(sockfd, (char *) httpRequestString, sizeof( httpRequestString ),0);

    while ( tmpres < sizeof( httpRequestString ) )

    {

        printf("Part of command sent, sending the rest\n");

        tmpres = send(sockfd, (char*)(httpRequestString+sent), (strlen(httpRequestString)-sent), 0);

        if (tmpres == RTCS_ERROR)

        {

            errCode = RTCS_geterror(sockfd);

            printf("\nCan't send query. Error:%x\n",errCode);

            return ERROR;

        }

        sent += tmpres;

    }

    printf("Command send to server:- %s\n",httpRequestString);

    _time_delay(100);   

    /* ready to receive data from the server */

    memset(recvBuf, 0, sizeof(recvBuf) );

    while ((tmpres = recv(sockfd, recvBuf, sizeof(recvBuf), 0)) > 0)

    {

        numBytes += tmpres;

        recvBuf[tmpres] = 0;     /* for test assuming receiving a html page, this can be printed */

        printf("%s\n",recvBuf);

        printf("Packet received of %d Bytes Total Bytes Received %d\n",tmpres,numBytes);

    }

    /* Display error code */

    if ( tmpres == RTCS_ERROR )

    {

        errCode = RTCS_geterror(sockfd);

        printf("\nReceive Error:%x\n",errCode);

    }

    if ( tmpres == 0 )

        printf("No more data to receive from socket\n");

    /*shutdown(sockfd, FLAG_CLOSE_TX);*/

    shutdown(sockfd, FLAG_ABORT_CONNECTION);

}

 

The only things you need to change are as follows: -

The client address to your Web Server i.e. you can try MQX web server on the same board as a working example, and then try a different web server

/* http client address*/

#define CAADD1    172

#define CAADD2    18

#define CAADD3    11

#define CAADD4    11

/* For Freescales MQX Web Server Example */

static const char httpRequestString[] = {"\

GET /rtc.html HTTP/1.0\r\n\

Host: 172.18.11.11\r\n\r\n"};

Notes:- Access to external web pages (i.e. www.freescale.com) may be block by your companies firewall, best to try internal webpages i.e net work printer etc


You help is very much appreciated…

Thanks rick101

For back ground info and a link to the twitter example

https://community.freescale.com/thread/301508

Updated to add version 2, correct some error handling, added sock time out option, some new results see below

Original Attachment has been moved to: httpdsrv_VER2.c.zip
Original Attachment has been moved to: httpdsrv.c.zip

Labels (1)
0 Kudos
5 Replies

1,412 Views
karelm_
Contributor IV

Hi rick,

there are few problems in your code which may cause you code to not function properly:

1. while ((tmpres = recv(sockfd, recvBuf, sizeof(recvBuf), 0)) > 0). You are saving return value of recv() to unsigned variable. This will make code inside conditions in your while loop impossible to reach, because value of RTCS_SOCKET_ERROR is -1 and variable tmpres will be always greater than zero in that loop.

2. There are multiple cases in which return value of recv() is zero. It can mean temporary error in RTCS. Also you are using blocking call of recv() (without timeout). So it should return only if there are some data in buffer.

3. You should stop reading from the socket only after you get all the data you are expecting (or if there is permanent socket error). In HTTP you can get information about number of bytes send to you from Content-Length member of the HTTP header.

Best regards,

Karel

0 Kudos

1,412 Views
rick101
Contributor III

Thanks Karel

"1. while ((tmpres = recv(sockfd, recvBuf, sizeof(recvBuf), 0)) > 0). You are saving return value of recv() to unsigned variable. This will make code inside conditions in your while loop impossible to reach, because value of RTCS_SOCKET_ERROR is -1 and variable tmpres will be always greater than zero in that loop."

Totally agree…..  I noticed this as well; the code comes from the twitter example which I left the same (there are other issues with the twitter example as well). I’ve made some minor changes and added source code to the first page to download - version 2

"2. There are multiple cases in which return value of recv() is zero. It can mean temporary error in RTCS. Also you are using blocking call of recv() (without timeout). So it should return only if there are some data in buffer."

For the above example, I only want data if the buffer contains some, normally request and receive data…  I’ve added the socket time out option for 10 seconds,useful for future error handling

3. You should stop reading from the socket only after you get all the data you are expecting (or if there is permanent socket error). In HTTP you can get information about number of bytes send to you from Content-Length member of the HTTP header.


Agree… (a) but the Content-Length is not always returned…....   (b) in this case for linux, qnx and windows etc, a receive length of 0 indicates transmission has been completed for MQX, a  successful transfer MQX returns #define RTCSERR_TCP_CONN_CLOSING (RTCS_ERROR_BASE|0x638)  /* Connection closing          */ which is okay, can handle this



Some new results....., I've found it works on some servers and not others seen below


Case 1 - Does not work - getting the status page from a dell printer, error code received 1649 –  socket time (due to the socket time out option)

i.e. response received “HTTP/1.0 200 OK” and no data??????? - where has it gone


Case 2  - Seems to workMitrrefinch time management web server

Terminal output

Connected to 172.18.2.59, port 80.

Command send to server:- GET /tmsnet/DEFAULT.ASPX?authenticate=false&tgglStr=&ReturnURL= HTTP/1.0

Host: 172.18.2.59

HTTP/1.1 200 OK

Cache-Control: no-cache

Pragma: no-cache

Content-Length: 4821

Content-Type: text/html; charset=utf-8

Expires: -1

Server: Microsoft-IIS/7.5

X-AspNet-Version: 1.1.4322

Set-Cookie: ASP.NET_SessionId=x4of10egxzfj1k45rbkqqe55; path=/

Set-Cookie: .ASPXAUTH=; expires=Mon, 11-Oct-1999 23:00:00 GMT; path=/

X-Powered-By: ASP.NET

Date: Tue, 09 Jul 2013 13:01:29 GMT

Connection: close

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01


etc

etc

Tried difference servers, some only return partial pages, followed by socket time out?


0 Kudos

1,412 Views
karelm_
Contributor IV

Hi rick101,

HTTP server from MQX 3.8.1 (called HTTPD) is now obsoleted feature of the RTCS (it has a lot of bugs). It will be replaced by new implementation (named HTTPSRV) in next MQX release (4.0.2). HTTPSRV will have different API, example and documentation, so you can use it as soon as it is released.

Best regards,

Karel

0 Kudos

1,412 Views
rick101
Contributor III

Thanks Karel for your responce... The issue we have is with TCP / IP socket client and not the HTTP server, we just built the test code on top of this mqx http server example so people can can easliy test this simple socket client example. We have tried this standalone with the same result. The TCP/IP client should have no idea of the higher level protocols, it does not care.  We can't move to MQX 4.x at the moment.

Is any one able to test the above example? or any other info ... thanks

0 Kudos

1,412 Views
rick101
Contributor III

Corrected Code Warrior Version used, any help

0 Kudos