TCP Server Connecct Warning?

15 Mar 2012

I am in the process of modifying the TCP Server example found on the mbed site into a telnet server to provide remote interactive access to my application. The code modification went well and works with a few dummy commands as placeholders. When I compile this code I receive the warning message shown below:

Description                                      Resource      Location
---------------------------------------------------------------------------------
transfer of control bypasses initialization of:  10_telnet.c   Line: 142, Col: 15

This telnet code seems to work OK with what little testing I've done, but I am concerned by this message that "onListening TCPSocketEvent()" may at sometime be called before it is initialized. I think I am initializing, binding the port, and checking for errors properly as in "TEL_init()" below. I have initialized "EthernetNetIf eth;" in an earlier routine to get an IP address.

What is spooking the compiler? Should I be concerned about this warning being a latent bug sometime in the future?

141: void onListeningTCPSocketEvent(TCPSocketEvent e) 
142:     switch (e) {

//*****************************************************************************
// Telnet Server
//*****************************************************************************

#include "mbed.h"
#include "EthernetNetIf.h"
#include "TCPSocket.h"

extern DigitalOut led4;
extern EthernetNetIf eth;

TCPSocket ListeningSock;
TCPSocket* pConnectedSock; // for ConnectedSock
Host client;
TCPSocketErr err;
Timer tel_tmr;

#define TELNET_LISTENING_PORT 12345

void onConnectedTCPSocketEvent(TCPSocketEvent e);
void onListeningTCPSocketEvent(TCPSocketEvent e);

//---------------------------------------------------------------------------------------
// TEL_init - Initialize telenet port
//---------------------------------------------------------------------------------------
int TEL_init(void) 
{
    printf("TEL: Initializing telnet port...\r\n");
    IpAddr ip = eth.getIp();
    ListeningSock.setOnEvent (&onListeningTCPSocketEvent);             // Set the callbacks for Listening
    err = ListeningSock.bind (Host(IpAddr(), TELNET_LISTENING_PORT));  // bind and listen on TCP
    
    if (err) {
        printf("TEL: Port binding error: %d\r\n", err);              // Deal with that error...
    }
    else {    
        err=ListeningSock.listen();                                    // Start listening
        if (err) {
            printf("TEL: Listening Error: %d\r\n", err);
        }
        else {
            printf("TEL: Now listening on: %d.%d.%d.%d:%d\r\n", 
                    ip[0], ip[1], ip[2], ip[3], TELNET_LISTENING_PORT);
            tel_tmr.start();
        }
    }
    return(0);
}

//---------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------
void TEL_Poll (void)
{
    Net::poll();
    if (tel_tmr.read() > 0.2) { // sec
        led4=!led4; //Show that we are alive
        tel_tmr.reset();
    }
}

//---------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------
void telnet_command_handler(char* telBfr, int len) {

    printf("Received %c, length = %d\r\n", telBfr[0], len);

    switch (telBfr[0]) 
    {
        case 'a':
            strcpy (telBfr, "a: Hello from Telnet Server.\r\n");
            break;

        case 'b':
            strcpy (telBfr, "b: Telnet Server.\r\n");
            break;

        case 'c':
            strcpy (telBfr, "c: Telnet Server.\r\n");
            break;

        case 'd':
            strcpy (telBfr, "d: Good Bye!\r\n");
            break;

        default:
            strcpy (telBfr, "?\r\n");
            break;
    }
    
    len = strlen(telBfr);
    pConnectedSock->send(telBfr, len);
    printf("Send len = %d\r\n", len);
    printf("Received&Wrote:%s\r\n",telBfr);
}

//---------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------
void onConnectedTCPSocketEvent(TCPSocketEvent e) {
    switch (e) 
    {
        case TCPSOCKET_CONNECTED:
            printf("TCP Socket Connected\r\n");
            break;
        case TCPSOCKET_WRITEABLE:
            //Can now write some data...
            printf("TCP Socket Writable\r\n");
            break;
        case TCPSOCKET_READABLE:
            //Can now read dome data...
            printf("TCP Socket Readable\r\n");
            // Read in any available data into the buffer
            char buff[128];
            while ( int len = pConnectedSock->recv(buff, 128) ) {
                telnet_command_handler(buff, len);
            }
            break;
        case TCPSOCKET_CONTIMEOUT:
            printf("TCP Socket Timeout\r\n");
            break;
        case TCPSOCKET_CONRST:
            printf("TCP Socket CONRST\r\n");
            break;
        case TCPSOCKET_CONABRT:
            printf("TCP Socket CONABRT\r\n");
            break;
        case TCPSOCKET_ERROR:
            printf("TCP Socket Error\r\n");
            break;
        case TCPSOCKET_DISCONNECTED:
            //Close socket...
            printf("TCP Socket Disconnected\r\n");
            pConnectedSock->close();
            break;
        default:
            printf("DEFAULT\r\n");
    }
}

//---------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------
void onListeningTCPSocketEvent(TCPSocketEvent e) {
    switch (e) {
        case TCPSOCKET_ACCEPT:
            printf("Listening: TCP Socket Accepted\r\n");
            // Accepts connection from client and gets connected socket.
            err=ListeningSock.accept(&client, &pConnectedSock);
            if (err) {
                printf("onListeningTcpSocketEvent : Could not accept connection.\r\n");
                return; //Error in accept, discard connection
            }
            // Setup the new socket events
            pConnectedSock->setOnEvent(&onConnectedTCPSocketEvent);
            // We can find out from where the connection is coming by looking at the
            // Host parameter of the accept() method
            IpAddr clientIp = client.getIp();
            printf("Listening: Incoming TCP connection from %d.%d.%d.%d\r\n",
                   clientIp[0], clientIp[1], clientIp[2], clientIp[3]);
            break;
            // the following cases will not happen
        case TCPSOCKET_CONNECTED:
            printf("Listening: TCP Socket Connected\r\n");
            break;
        case TCPSOCKET_WRITEABLE:
            printf("Listening: TCP Socket Writable\r\n");
            break;
        case TCPSOCKET_READABLE:
            printf("Listening: TCP Socket Readable\r\n");
            break;
        case TCPSOCKET_CONTIMEOUT:
            printf("Listening: TCP Socket Timeout\r\n");
            break;
        case TCPSOCKET_CONRST:
            printf("Listening: TCP Socket CONRST\r\n");
            break;
        case TCPSOCKET_CONABRT:
            printf("Listening: TCP Socket CONABRT\r\n");
            break;
        case TCPSOCKET_ERROR:
            printf("Listening: TCP Socket Error\r\n");
            break;
        case TCPSOCKET_DISCONNECTED:
            //Close socket...
            printf("TEL: Listening port %d disconnected\r\n", TELNET_LISTENING_PORT);
            ListeningSock.close();
            break;
        default:
            printf("DEFAULT\r\n");
    }
}
16 Mar 2012

Doug,

I see that the quoted code snippet associated with the error message has no opening (left) curly brace between lines 141 and 142. As is often the case, the compiler keeps on trying to make sense of what it does find, and does not report an error until the end of line 142.

Could there be some sort of editing or version control snafu that causes the compiler to scan a different version of your source than what you have posted?

16 Mar 2012

Fred,

I evidently posted the the code snippet incorrectly and eliminated the left brace while editing. The actual code shown in the third code block does have the left curly brace. Thanks for noting that descrepancy, however.

141: void onListeningTCPSocketEvent(TCPSocketEvent e) 
142:     switch (e) {

 ---
 ---

void onListeningTCPSocketEvent(TCPSocketEvent e) {
    switch (e) {

I think the compiler is somehow thinking that the "onListening" event handler may be activated by some TCP activity before it has been initialized. However, TEL_init() should take care of that in that it first binds the port, and last initiated listening on that port. Prior to that I would think that TCP activity would be ignored for that port. (Simin Ford, can you weigh in on this?) Thanks.

11 Jun 2012

I've run into the same issue.

The original program that I leeched produces the same warning (http://mbed.org/users/xshige/programs/TCP_server/leamu9).

Is this bad? Will it kill me?

The program works, I just like to have a clean build log :)

11 Jun 2012

The original poster's code is declaring a variable (clientIp) at the scope of the switch in one of the case statements. This variable is visible to ALL the cases, but will only get initialized by one of them - that is what the compiler is cranky about. That variable is really only intended to be used in a single case, so it should be scoped only to that case - for example:

switch (e)
{
case 0:
    int i = 0;  //  this is at 'switch' scope - don't do this!
    break;
case 1:
    if (1)
    {
        int j = 0;  //  this is at the 'case' scope 
    }
    break;
}

I will often do this if the compiler allows (although it's kind of cheating):

switch (e)
{
    case 0:  //  following braces don't really 'belong' to the case statement
    {        //  they are an independent scope, but we like the way this looks
        int i = 0;
        break;  //  this breaks out of the switch statement, not just the scope
    }
}

There is another potential warning (although the compiler doesn't seem to mind) - there are global values that aren't initialized, which get used by the network handler functions. Although you and I know that they get set in the main() function before the handlers ever get called, the compiler doesn't know that.

So any global that is not a class instance and has its value used in a handler should get initialized. In this case the variable is pConnectedSock, and its declaration should be:

TCPSocket* pConnectedSock = 0;
14 Jun 2012

agilent mbed wrote:

So any global that is not a class instance and has its value used in a handler should get initialized. In this case the variable is pConnectedSock, and its declaration should be:

Code TCPSocket* pConnectedSock = 0;

While I personally like to see all globals initialized like this to make their initial value clearer, it isn't required as globals are initialized to 0 by the C runtime if you don't give them an explicit value when you define them.