Problem with select() operation... - VxWorks

This is a discussion on Problem with select() operation... - VxWorks ; I have a routine to do standard tcp/ip socket communications with a pair of Modicon PLC's. I've run into a bit of a snag, in that if I do something simple like unplugging the ethernet cable from one of my ...

+ Reply to Thread
Results 1 to 3 of 3

Thread: Problem with select() operation...

  1. Problem with select() operation...

    I have a routine to do standard tcp/ip socket communications with a pair
    of Modicon PLC's. I've run into a bit of a snag, in that if I do
    something simple like unplugging the ethernet cable from one of my
    PLC's, my program hangs, waiting for communications to be restored.

    Here's the section of code where this happens:

    /* Check ready to send */

    if(plc_num == 1)
    selected = select(32, NULL, &socket1fd, NULL, &timer);
    else
    selected = select(32, NULL, &socket2fd, NULL, &timer);

    if(selected <= 0)
    {
    strcpy(error_message, "No TCP/IP response was received");
    Log_Message(error_message);
    return read_err;
    }
    else if(selected == 0)
    {
    printf("Timed Out\n"); /* was dprintf */
    return timed_out;
    }
    else
    {
    nbytes = recv(sckt, resp, 261,0);
    if (nbytes == 0)
    {
    printf("unexpected close of connection at remote end\n");
    return read_err;
    }
    else if (nbytes == ERROR )
    {
    printf("Read_Error! Nbytes = %d\n", nbytes); /* was dprintf */
    return read_err;
    }
    else if ((resp[7] && error_bitmask) == error_bitmask)
    {
    printf("TCP/IP modbus protocal error\n"); /* was dprintf */
    return read_err;
    }
    else
    {
    s = wdCancel(plc_timer);
    Append_Circbuf(cbuf, resp);
    return success;
    }
    }
    }

    Where I get the hang problem is with the "recv" statement. I may
    be completely mistaken in how the select operation works, but I expected
    that if the other end of the socket was not viable, I would have timed
    out on the select() command. But regardless of whether my connection is
    legitimate or not, the select command gives the same response and allows
    the program to continue.

    Any help would be most appreciated. Thanks in advance...

    dave

  2. Re: Problem with select() operation...

    Dave Reid wrote:
    > I have a routine to do standard tcp/ip socket communications with a pair
    > of Modicon PLC's. I've run into a bit of a snag, in that if I do
    > something simple like unplugging the ethernet cable from one of my
    > PLC's, my program hangs, waiting for communications to be restored.


    Hi Dave,

    I see a few problems with the code at a glance, and then there are some
    things that are uncertain.

    > Here's the section of code where this happens:


    > /* Check ready to send */


    > if(plc_num == 1)
    > selected = select(32, NULL, &socket1fd, NULL, &timer);
    > else
    > selected = select(32, NULL, &socket2fd, NULL, &timer);
    >


    I take it that socket1fd and socket2fd are 'fd_set's. Are their contents
    reset prior to each call to select()?

    Is 32 - 1 what NUM_FILES is set to? I don't recall if that corresponds to the
    highest file descriptor that will be issued. It is safer to search through
    the list of file descriptors to be examined, and add one to the greatest
    value found.

    > if(selected <= 0)
    > {
    > strcpy(error_message, "No TCP/IP response was received");
    > Log_Message(error_message);
    > return read_err;
    > }
    > else if(selected == 0)


    This section will never be reached due to the previous test. That is,
    timeouts and error will be indistinguishable.

    > {
    > printf("Timed Out\n"); /* was dprintf */
    > return timed_out;
    > }
    >


    else
    > {
    > nbytes = recv(sckt, resp, 261,0);


    Is sckt the file descriptor (and the only one at that) added to the tested
    fd_set?

    > if (nbytes == 0)
    > {
    > printf("unexpected close of connection at remote end\n");
    > return read_err;
    > }
    > else if (nbytes == ERROR )
    > {
    > printf("Read_Error! Nbytes = %d\n", nbytes); /* was dprintf */
    > return read_err;
    > }
    > else if ((resp[7] && error_bitmask) == error_bitmask)


    There is no guarantee that the entire message was read. It may be that only
    the first byte is valid. If this is a TCP socket, a subsequent recv() might
    be necessary. If it is a UDP message, the code should validate that the size
    of the message is as expected.

    > {
    > printf("TCP/IP modbus protocal error\n"); /* was dprintf */
    > return read_err;
    > }
    > else
    > {
    > s = wdCancel(plc_timer);
    > Append_Circbuf(cbuf, resp);


    Again, the data stored in resp might only have a single valid byte.

    > return success;
    > }
    > }
    > }


    > Where I get the hang problem is with the "recv" statement. I may
    > be completely mistaken in how the select operation works, but I expected
    > that if the other end of the socket was not viable, I would have timed
    > out on the select() command. But regardless of whether my connection is
    > legitimate or not, the select command gives the same response and allows
    > the program to continue.


    Can you elaborate on the response seen?

    > Any help would be most appreciated. Thanks in advance...


    > dave


  3. Re: Problem with select() operation...

    Jeremy wrote in news:dvvh56$bk5$1@reader2.panix.com:

    >> Here's the section of code where this happens:

    >
    >> /* Check ready to send */

    >
    >> if(plc_num == 1)
    >> selected = select(32, NULL, &socket1fd, NULL, &timer);
    >> else
    >> selected = select(32, NULL, &socket2fd, NULL, &timer);
    >>

    >
    > I take it that socket1fd and socket2fd are 'fd_set's.


    Here's how "socket1fd" and "socket2fd" are setup"

    static int sckt1;
    static int sckt2;

    /* Set up the server_addr structure for Mod 1 */
    plc_module1.sin_family = AF_INET;
    plc_module1.sin_port = htons(502); /* ASA Standard Port */
    plc_module1.sin_addr.s_addr = inet_addr(ip_adrs_mod1);

    /* Set up the server_addr structure for Mod 2 */
    plc_module2.sin_family = AF_INET;
    plc_module2.sin_port = htons(502); /* ASA Standard Port */
    plc_module2.sin_addr.s_addr = inet_addr(ip_adrs_mod2);

    /* timeout for connectWithTimeout */
    connect_timeout.tv_sec = 10;
    connect_timeout.tv_usec = 0;

    /* Establish socket for Modicon 1 */
    /* Need to allocate new socket number for connect to retry correctly */
    while((connect_attempts <= 20) && (ic < 0))
    {
    /* establish connection to gateway on ASA standard port 502 */
    if ((sckt1 = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
    printf("Client Side Socket Error -- Could Not Obtain Socket for
    Modicon 1\n");

    /* Now try to connect */
    printf("Attempt #%d:Connecting to Modicon 1 with a %d second timeout
    \n", connect_attempts, connect_timeout.tv_sec);
    ic = connectWithTimeout(sckt1, (struct sockaddr *)&plc_module1,
    sizeof (struct sockaddr_in), &connect_timeout);
    connect_attempts++;
    if (ic < 0)
    {
    delay(1,0);
    printf("Control Program could not open TCP/IP socket %d to
    Modicon PLC 1!\n", sckt1);
    close(sckt1);
    }
    else
    {
    printf("TCP/IP socket open to Modicon PLC 1\n");
    }
    }

    if(ic < 0)
    {
    printf("Control Program unable to open TCP/IP socket to Modicon 1
    \n");
    return open_err;
    }

    And then the same thing for the second socket.

    > Are their
    > contents reset prior to each call to select()?


    No...

    >> if(selected <= 0)
    >> {
    >> strcpy(error_message, "No TCP/IP response was received");
    >> Log_Message(error_message);
    >> return read_err;
    >> }
    >> else if(selected == 0)

    >
    > This section will never be reached due to the previous test. That is,
    > timeouts and error will be indistinguishable.


    You are right...I'll have to fix that.

    > Is sckt the file descriptor (and the only one at that) added to the
    > tested fd_set?


    Yes...

    > There is no guarantee that the entire message was read. It may be
    > that only the first byte is valid. If this is a TCP socket, a
    > subsequent recv() might be necessary.


    I don't have any problems with that. In fact, this code has been
    running just fine for years. But just recently, we were doing some work
    on our Modicon and unplugged the ethernet cable, and then realized that
    this other program hadn't timed out like we expected it too. So we
    started to investigate why...

    >> Where I get the hang problem is with the "recv" statement. I
    >> may
    >> be completely mistaken in how the select operation works, but I
    >> expected that if the other end of the socket was not viable, I would
    >> have timed out on the select() command. But regardless of whether my
    >> connection is legitimate or not, the select command gives the same
    >> response and allows the program to continue.

    >
    > Can you elaborate on the response seen?


    From the select statement, I get a "1" as the returned value if
    the cable is connected or disconnected.

    Thanks for the response.

    dave

+ Reply to Thread