select() returns 0 immediately on non-blocking AF_PACKET socket ignoring timeval

296 views Asked by At

My Linux code below is supposed to search all interfaces until it gets a response from a particular MAC address using ETHERNET type 2 frames.

It is not complete.

I want select() to block for the time out value. Problem is with no packets coming in it returns zero with no delay. Am I getting something wrong here?

//------------------------------------------------------------------------------------------------------------------
// create Ethernet buffers and variables.

char*       outBuff = NULL;  // character buffer for sending out on Ethernet.  
size_t      outBuffSz = 256;

char*       inBuff = NULL;   // character buffer for receiving in on Ethernet. 
size_t      inBuffSz = 256;

int         fd;              // file descriptor for socket.

int         flags;           // socket flags used bt fcntl().

struct
ifreq       ifr;             // used to get and set interface parameters.

struct
sockaddr_ll IOM_sa_flt;      // socket address struct, used to filter received Ethernet frames from the remote IO module ... used by bind().

struct
sockaddr_ll IOM_sa_rcv;      // socket address struct, used to store addr details of received frame.
socklen_t   IOM_sa_len;      // IOM_sa_rcv length.

fd_set      myfds;           // used by select().

struct
timeval     rcv_tm_out;      // time out for select() to declare communications failed.



//------------------------------------------------------------------------------------------------------------------
// initialize Ethernet buffers and variables.

// allocate memory for the Ethernet sending message buffer.
outBuff = malloc(outBuffSz);
if (outBuff == NULL)
  printf("\nNATIVE-PLCThread: Could not allocate outBuff memory.");
memset(outBuff, '\0', outBuffSz);

// allocate memory for the Ethernet recevied message buffer.
inBuff = malloc(inBuffSz);
if (inBuff == NULL)
  printf("\nNATIVE-PLCThread: Could not allocate inBuff memory.");
memset(inBuff, '\0', inBuffSz);

// clear the sockaddr_ll structs.
// (send was already cleared ... it is inside the PLC typdef).
memset(&IOM_sa_rcv, 0, sizeof(IOM_sa_rcv));
memset(&IOM_sa_flt, 0, sizeof(IOM_sa_flt));

// set receiving sockaddr_ll struct size.
IOM_sa_len = sizeof(IOM_sa_rcv);

// setup the sending, receiving, and filtering sockaddr_ll's.
myPLC->IOM_sa_snd.sll_family    = AF_PACKET;
myPLC->IOM_sa_snd.sll_protocol  = htons(eType);

IOM_sa_rcv.sll_family    = AF_PACKET;
IOM_sa_rcv.sll_protocol  = htons(eType);

IOM_sa_flt.sll_family    = AF_PACKET;
IOM_sa_flt.sll_protocol  = htons(eType);



//------------------------------------------------------------------------------------------------------------------
// open our socket in dgram mode and setup the socket's features.
fd = socket(AF_PACKET, SOCK_DGRAM, htons(ETH_P_ALL));
if (fd == -1)
{
  fprintf(stderr, "%s\n", strerror(errno));
  printf("\nNATIVE-PLCThread: socket() failed !! - ");
}
// get the socket file descriptor flags.
flags = fcntl(fd, F_GETFL, 0);

// if succesful, set to non-blocking.
if (flags != -1)
  fcntl(fd, F_SETFL, flags | O_NONBLOCK);

// get 'Ethernet Init' code execute time and store.
gettimeofday (&endPhase, NULL);
eInitT = (endPhase.tv_sec - startPhase.tv_sec)*1000000L + endPhase.tv_usec - startPhase.tv_usec;

//------------------------------------------------------------------------------------------------------------------
// if configured, loop to find the IOM_MacAddr on the Ethernet and set the correct interface parameters.
if (myPLC->MAC_is_Valid == 0xa5)
{
  if (fd != -1) // valid socket fd means ok to proceed.
  {
    // fill outBuff with the hello message.
    strncpy(outBuff, "Hello?", sizeof("Hello?"));

    // begin for loop ----------------------------------------------------------------------------------------------
    //
    //  IOM_MAC_search
    //
    // find the network interface that has our IO Module's Mac Address.
    for (i = 1; 1; i++)
    {
      // we need to test for thread kill signal.
      if((myPLC->ThreadCtrl == SIGNAL_THREAD_KILL) || (myPLC->ThreadCtrl == SIGNAL_THREAD_RESET)) break;

      // clear the ifreq struct.
      memset(&ifr, 0, sizeof(ifr));

      // i is our 'for' loop counter and our current interface index.
      ifr.ifr_ifindex = i;

      // does the interface exist?
      if (ioctl(fd, SIOCGIFNAME, &ifr) == -1)
      {
        // if not, we ran past top of network interfaces.
        printf("\nNATIVE-PLCThread: IOM_MAC_search MAC address not found after searching %d interfaces !!!\n", i-1);
        //break;    // un-comment for single search of all interfaces, comment for infinite search (engine loop never runs !!!).
        sleep(5);   // comment for single search of all interfaces, un-comment for infinite search (engine loop never runs !!!).
        i = 0;    // comment for single search of all interfaces, un-comment for infinite search (engine loop never runs !!!).
        continue;   // comment for single search of all interfaces, un-comment for infinite search (engine loop never runs !!!).
      }
      else  // ifr has interface name (required for all other ioctl).
      {
        // if so, store the ifname using the pointer.
        strncpy (myPLC->ifName, ifr.ifr_name, sizeof(ifr.ifr_name) - 1);
        myPLC->ifName[IFNAMSIZ - 1] = '\0';

        // update the interface index in all sockaddr structs.
        myPLC->IOM_sa_snd.sll_ifindex = i;
        IOM_sa_rcv.sll_ifindex = i;
        IOM_sa_flt.sll_ifindex = i;
      }

      // is the interface up?
      ioctl(fd, SIOCGIFFLAGS, &ifr);
      if ((ifr.ifr_flags & IFF_UP) == 0)
      {
        printf("\nNATIVE-PLCThread: IOM_Addr_search interface %s (index %d) is down.\n", myPLC->ifName, i);
        continue;
      }

      // bind it.
      if (bind(fd, (struct sockaddr*)&IOM_sa_flt, sizeof(IOM_sa_flt)) == -1)
      {
        fprintf(stderr, "%s\n", strerror(errno));
        printf("\nNATIVE-PLCThread: IOM_Addr_search bind() failed  !!!\n");
        continue;
      }
      // send hello msg to the IOM with configured IOM_MAC_address.
      if (sendto(fd, outBuff, sizeof("Hello?"), 0, (struct sockaddr *)&(myPLC->IOM_sa_snd), sizeof (myPLC->IOM_sa_snd)) == -1)
      {
        fprintf(stderr, "%s\n", strerror(errno));
        printf("\nNATIVE-PLCThread: IOM_Addr_search sendto() failed !!!\n");
        continue;
      }

      // setup for the select() time out loop.
      rcv_tm_out.tv_sec = 60;
      rcv_tm_out.tv_usec = 0;

      // select() time out loop.
      while ((rcv_tm_out.tv_sec != 0) || (rcv_tm_out.tv_usec != 0))
      {
        // create the file descriptor set for use by select().
        FD_ZERO(&myfds);
        FD_SET(fd, &myfds);
        // select() to sleep until received frame is ready, or the maximum length of time it would taked to get a response is exceeded.
        printf("\nNATIVE-PLCThread: IOM_Addr_search, calling select() rcv_tm_out.tv_sec = %d.\n", (int)rcv_tm_out.tv_sec);
        if (rtn = select(fd + 1, &myfds, NULL, NULL, &rcv_tm_out) < 0)
        {
          fprintf(stderr, "%s\n", strerror(errno));
          printf("\nNATIVE-PLCThread: IOM_Addr_search select() returned <0 on interface %s (index %d).\n", myPLC->ifName, i);
          break;
        }
        // did we time out? ... then goto the next interface to search.
        else if (rtn == 0)
        {
          printf("\nNATIVE-PLCThread: IOM_Addr_search select() returned 0 on interface %s (index %d) rcv_tm_out.tv_sec = %d.\n", myPLC->ifName, i, (int)rcv_tm_out.tv_sec);
          break;
        }
        else  // select() returned > 0.
        {
          printf("\nNATIVE-PLCThread: IOM_Addr_search select() returned >0 on interface %s (index %d).\n", myPLC->ifName, i);
          if (FD_ISSET(fd, &myfds))
          {
            printf("\nNATIVE-PLCThread: IOM_Addr_search select() ... inside a_file_descriptor_is_set code!\n");
            // our socket is ready for reading.
            if(rtn = recvfrom(fd, inBuff, inBuffSz, 0, (struct sockaddr *)&IOM_sa_rcv, &IOM_sa_len) < 0)
            {
              if (errno == EAGAIN)
                printf("\nNATIVE-PLCThread: IOM_Addr_search recvfrom() returned EAGAIN.\n");
              else if (errno == EWOULDBLOCK)
                printf("\nNATIVE-PLCThread: IOM_Addr_search recvfrom() returned EWOULDBLOCK.\n");
              else
              {
                fprintf(stderr, "%s\n", strerror(errno));
                printf("\nNATIVE-PLCThread: IOM_Addr_search recvfrom() returned unrecoverable error.\n");
              }
              break;
            }
            else if (rtn == 0)
              printf("\nNATIVE-PLCThread: IOM_Addr_search a_file_descriptor_is_set yet recvfrom() returned zero.\n");
            else  // recvfrom() returned > 0.
            {
            printf("\nNATIVE-PLCThread: IOM_Addr_search recvfrom() returned %d bytes.\n", rtn);
            // parse the received response to our hello msg.
            // check the IOM_sa_rcv.MAC_Addr ... is it what we expect?
            // if (good hello) then ... 
                // declare ComStatus ok.
                //myPLC->ComStatus = 0xa5;
                //break;    // done searching since we found it.
            // else myPLC->ComStatus = 0x5a;
            }
          }
          else printf("\nNATIVE-PLCThread: IOM_Addr_search select() returned > 0 yet our only file descriptor was not set !!!\n");
        }
      }// END while loop -------------------------------------------------------------------------------------------
    }// END for loop -----------------------------------------------------------------------------------------------
  }// END "valid socket fd means ok to proceed" --------------------------------------------------------------------
  else printf("\nNATIVE-PLCThread: IOM_Addr_search socket() previously failed ... search cannot proceed.\n");
}// END MAC_is_Valid test" -----------------------------------------------------------------------------------------
else printf("\nNATIVE-PLCThread: IOM_Addr_search invalid IOM_MAC_address ... search cannot proceed.\n");
1

There are 1 answers

0
DurararaC On BEST ANSWER

wildplasser called it ... rookie mistake.

Missed parenthesis in two if's.