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");
wildplasser called it ... rookie mistake.
Missed parenthesis in two if's.