added timeout to the ethernet receive

This commit is contained in:
skarg
2005-04-18 20:53:02 +00:00
parent 3b8cfb87ef
commit d6033b03a3
3 changed files with 110 additions and 18 deletions
+2 -1
View File
@@ -69,7 +69,8 @@ int ethernet_send_pdu(
uint16_t ethernet_receive(
BACNET_ADDRESS *src, // source address
uint8_t *pdu, // PDU data
uint16_t max_pdu); // amount of space available in the PDU
uint16_t max_pdu, // amount of space available in the PDU
unsigned timeout); // milliseconds to wait for a packet
void ethernet_get_my_address(BACNET_ADDRESS *my_address);
+99 -12
View File
@@ -32,14 +32,57 @@
-------------------------------------------
####COPYRIGHTEND####*/
#include <stdio.h> /* Standard I/O */
#include <stdlib.h> /* Standard Library */
#include <errno.h> /* Error number and related */
#include <stdint.h> // for standard integer types uint8_t etc.
#include <stdbool.h> // for the standard bool type.
#include <sys/types.h> /* System data types */
#include <unistd.h> /* Command-line options */
#include <string.h> /* string hanfling functions */
/* common unix sockets headers needed */
#include <sys/types.h> /* basic system data types */
#include <sys/time.h> /* timeval{} for select() */
#include <time.h> /* timespec{} for pselect() */
#include <netinet/in.h> /* sockaddr_in{} and other Internet defns */
#include <arpa/inet.h> /* inet(3) functions */
#include <errno.h>
#include <fcntl.h> /* for nonblocking */
#include <netdb.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h> /* for S_xxx file mode constants */
#include <sys/uio.h> /* for iovec{} and readv/writev */
#include <unistd.h>
#include <sys/wait.h>
#include <sys/un.h> /* for Unix domain sockets */
#ifdef HAVE_SYS_SELECT_H
# include <sys/select.h> /* for convenience */
#endif
#ifdef HAVE_POLL_H
# include <poll.h> /* for convenience */
#endif
#ifdef HAVE_STRINGS_H
# include <strings.h> /* for convenience */
#endif
/* Three headers are normally needed for socket/file ioctl's:
* <sys/ioctl.h>, <sys/filio.h>, and <sys/sockio.h>.
*/
#ifdef HAVE_SYS_IOCTL_H
# include <sys/ioctl.h>
#endif
#ifdef HAVE_SYS_FILIO_H
# include <sys/filio.h>
#endif
#ifdef HAVE_SYS_SOCKIO_H
# include <sys/sockio.h>
#endif
#ifdef HAVE_PTHREAD_H
# include <pthread.h>
#endif
#define ENUMS
#include <sys/socket.h>
@@ -89,6 +132,24 @@ void ethernet_cleanup(void)
return;
}
/*----------------------------------------------------------------------
Portable function to set a socket into nonblocking mode.
Calling this on a socket causes all future read() and write() calls on
that socket to do only as much as they can immediately, and return
without waiting.
If no data can be read or written, they return -1 and set errno
to EAGAIN (or EWOULDBLOCK).
Thanks to Bjorn Reese for this code.
----------------------------------------------------------------------*/
int setNonblocking(int fd)
{
int flags;
if (-1 == (flags = fcntl(fd, F_GETFL, 0)))
flags = 0;
return fcntl(fd, F_SETFL, flags | O_NONBLOCK);
}
/* opens an 802.2 socket to receive and send packets */
static int ethernet_bind(struct sockaddr *eth_addr, char *interface_name)
{
@@ -295,25 +356,51 @@ int ethernet_send_pdu(
uint16_t ethernet_receive(
BACNET_ADDRESS *src, // source address
uint8_t *pdu, // PDU data
uint16_t max_pdu) // amount of space available in the PDU
uint16_t max_pdu, // amount of space available in the PDU
unsigned timeout) // number of milliseconds to wait for a packet
{
int received_bytes;
uint8_t buf[MAX_MPDU] = {0}; // data
uint16_t pdu_len = 0; // return value
fd_set read_fds;
int max;
struct timeval select_timeout;
/* Make sure the socket is open */
if (eth802_sockfd <= 0)
return 0;
// FIXME: what about accept()?
/* we could just use a non-blocking socket, but that consumes all
the CPU time. We can use a timeout; it is only supported as
a select. */
if (timeout >= 1000)
{
select_timeout.tv_sec = timeout / 1000;
select_timeout.tv_usec =
1000 * (timeout - select_timeout.tv_sec * 1000);
}
else
{
select_timeout.tv_sec = 0;
select_timeout.tv_usec = 1000 * timeout;
}
FD_ZERO(&read_fds);
FD_SET(eth802_sockfd, &read_fds);
max = eth802_sockfd;
/* Attempt a read */
received_bytes = read(eth802_sockfd, &buf[0], MAX_MPDU);
if (select(max + 1, &read_fds, NULL, NULL, &select_timeout) > 0)
received_bytes = read(eth802_sockfd, &buf[0], MAX_MPDU);
else
return 0;
/* See if there is a problem */
if (received_bytes < 0) {
fprintf(stderr,"ethernet: Read error in receiving packet: %s\n",
strerror(errno));
// EAGAIN Non-blocking I/O has been selected
// using O_NONBLOCK and no data
// was immediately available for reading.
if (errno != EAGAIN)
fprintf(stderr,"ethernet: Read error in receiving packet: %s\n",
strerror(errno));
return 0;
}
+9 -5
View File
@@ -257,8 +257,10 @@ static void Init_Device_Parameters(void)
static void Init_Service_Handlers(void)
{
// custom handlers
apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_IS,WhoIsHandler);
// we need to handle who-is to support dynamic device binding
apdu_set_unconfirmed_handler(
SERVICE_UNCONFIRMED_WHO_IS,
WhoIsHandler);
// set the handler for all the services we don't implement
// It is required to send the proper reject message...
@@ -274,6 +276,7 @@ int main(int argc, char *argv[])
{
BACNET_ADDRESS src = {0}; // address where message came from
uint16_t pdu_len = 0;
unsigned timeout = 100; // milliseconds
Init_Device_Parameters();
Init_Service_Handlers();
@@ -281,15 +284,17 @@ int main(int argc, char *argv[])
if (!ethernet_init("eth0"))
return 1;
Send_IAm();
// loop forever
for (;;)
{
// input
// returns 0 bytes on timeout
pdu_len = ethernet_receive(
&src,
&Rx_Buf[0],
MAX_MPDU);
MAX_MPDU,
timeout);
// process
if (pdu_len)
@@ -307,7 +312,6 @@ int main(int argc, char *argv[])
// output
// blink LEDs, Turn on or off outputs, etc
}
return 0;