Added receive timeout via setsockopt(SO_RCVTIMEO)
git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@336 42af7a65-404d-4744-a932-0658087f49c3
This commit is contained in:
parent
09d6450ab3
commit
952db3328f
@ -199,7 +199,7 @@
|
|||||||
* examples/nsh/: Add cp, rm, rmdir, set, unset commands. echo will now print
|
* examples/nsh/: Add cp, rm, rmdir, set, unset commands. echo will now print
|
||||||
environment variables.
|
environment variables.
|
||||||
|
|
||||||
0.2.9 2007-xx-xx Gregory Nutt <spudmonkey@racsa.co.cr>
|
0.3.0 2007-xx-xx Gregory Nutt <spudmonkey@racsa.co.cr>
|
||||||
|
|
||||||
* Imported uIP into the tree (see
|
* Imported uIP into the tree (see
|
||||||
http://www.sics.se/~adam/uip/index.php/Main_Page)
|
http://www.sics.se/~adam/uip/index.php/Main_Page)
|
||||||
@ -209,4 +209,5 @@
|
|||||||
* Added recv() and recvfrom().
|
* Added recv() and recvfrom().
|
||||||
* Added getsockopt() and setsockopt()
|
* Added getsockopt() and setsockopt()
|
||||||
* Documentation updated to address socket interfaces.
|
* Documentation updated to address socket interfaces.
|
||||||
|
* Implemented receive timeouts via setsockopt(SO_RCVTIMEO).
|
||||||
|
|
||||||
|
@ -632,7 +632,7 @@ Other memory:
|
|||||||
</table>
|
</table>
|
||||||
|
|
||||||
<pre><ul>
|
<pre><ul>
|
||||||
0.2.9 2007-xx-xx Gregory Nutt <spudmonkey@racsa.co.cr>
|
0.3.0 2007-xx-xx Gregory Nutt <spudmonkey@racsa.co.cr>
|
||||||
|
|
||||||
* Imported uIP into the tree (see
|
* Imported uIP into the tree (see
|
||||||
http://www.sics.se/~adam/uip/index.php/Main_Page)
|
http://www.sics.se/~adam/uip/index.php/Main_Page)
|
||||||
@ -642,6 +642,7 @@ Other memory:
|
|||||||
* Added recv() and recvfrom().
|
* Added recv() and recvfrom().
|
||||||
* Added getsockopt() and setsockopt()
|
* Added getsockopt() and setsockopt()
|
||||||
* Documentation updated to address socket interfaces.
|
* Documentation updated to address socket interfaces.
|
||||||
|
* Implemented receive timeouts via setsockopt(SO_RCVTIMEO).
|
||||||
</pre></ul>
|
</pre></ul>
|
||||||
|
|
||||||
<table width ="100%">
|
<table width ="100%">
|
||||||
|
@ -67,7 +67,7 @@ struct dhcpc_state
|
|||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
void *dhcpc_open(const void *mac_addr, int mac_len);
|
void *dhcpc_open(const void *mac_addr, int mac_len);
|
||||||
int dhcpc_request(void *handle, struct dhcpc_state *ds);
|
int dhcpc_request(void *handle, struct dhcpc_state *presult);
|
||||||
void dhcpc_close(void *handle);
|
void dhcpc_close(void *handle);
|
||||||
|
|
||||||
#endif /* NET_UIP_DHCP_H__ */
|
#endif /* NET_UIP_DHCP_H__ */
|
||||||
|
@ -54,7 +54,7 @@ EXTERN void resolv_getserver(const struct sockaddr_in6 *dnsserver);
|
|||||||
EXTERN int resolv_query(const char *name, struct sockaddr_in6 *addr);
|
EXTERN int resolv_query(const char *name, struct sockaddr_in6 *addr);
|
||||||
#else
|
#else
|
||||||
EXTERN void resolv_conf(const struct sockaddr_in *dnsserver);
|
EXTERN void resolv_conf(const struct sockaddr_in *dnsserver);
|
||||||
EXTERN void resolv_getserver(const struct sockaddr_in *dnsserver);
|
EXTERN void resolv_getserver(struct sockaddr_in *dnsserver);
|
||||||
EXTERN int resolv_query(const char *name, struct sockaddr_in *addr);
|
EXTERN int resolv_query(const char *name, struct sockaddr_in *addr);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -1126,8 +1126,7 @@ extern int uip_udpconnect(struct uip_udp_conn *conn, const struct sockaddr_in *a
|
|||||||
|
|
||||||
/* This function is called user code to set up the wait */
|
/* This function is called user code to set up the wait */
|
||||||
|
|
||||||
#define uip_event_wait(waitflags) uip_event_timedwait(waitflags,0)
|
extern int uip_event_wait(uint16 waitflags);
|
||||||
extern int uip_event_timedwait(uint16 waitflags, int timeout);
|
|
||||||
|
|
||||||
/* This function is called from uip_interrupt() to wake up any
|
/* This function is called from uip_interrupt() to wake up any
|
||||||
* waiting threads/tasks.
|
* waiting threads/tasks.
|
||||||
|
108
net/recvfrom.c
108
net/recvfrom.c
@ -58,9 +58,15 @@
|
|||||||
|
|
||||||
struct recvfrom_s
|
struct recvfrom_s
|
||||||
{
|
{
|
||||||
sem_t rf_sem;
|
#if defined(CONFIG_NET_SOCKOPTS) && !defined(CONFIG_DISABLE_CLOCK)
|
||||||
uint16 rf_buflen;
|
FAR struct socket *rf_sock /* The parent socket structure */
|
||||||
char * rf_buffer;
|
#endif
|
||||||
|
sem_t rf_sem; /* Semaphore signals recv completion */
|
||||||
|
sint16 rf_buflen; /* Length of receive buffer (error if <0) */
|
||||||
|
char *rf_buffer; /* Pointer to receive buffer */
|
||||||
|
#if defined(CONFIG_NET_SOCKOPTS) && !defined(CONFIG_DISABLE_CLOCK)
|
||||||
|
uint32 rf_starttime; /* rcv start time for determining timeout */
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
@ -72,38 +78,61 @@ void recvfrom_interrupt(void *private)
|
|||||||
struct recvfrom_s *pstate = (struct recvfrom_s *)private;
|
struct recvfrom_s *pstate = (struct recvfrom_s *)private;
|
||||||
size_t recvlen;
|
size_t recvlen;
|
||||||
|
|
||||||
/* If new data is available and we are correctly intialized, then complete
|
/* 'private' might be null in some race conditions (?) */
|
||||||
* the read action. We could also check for POLL events here in order to
|
|
||||||
* implement SO_RECVTIMEO.
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (uip_newdata() && private)
|
if (pstate)
|
||||||
{
|
{
|
||||||
/* Get the length of the data to return */
|
/* If new data is available, then complete the read action. */
|
||||||
if (uip_len > pstate-> rf_buflen)
|
|
||||||
|
if (uip_newdata())
|
||||||
{
|
{
|
||||||
recvlen = pstate-> rf_buflen;
|
/* Get the length of the data to return */
|
||||||
}
|
if (uip_len > pstate-> rf_buflen)
|
||||||
else
|
{
|
||||||
{
|
recvlen = pstate-> rf_buflen;
|
||||||
recvlen = uip_len;
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
recvlen = uip_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Copy the appdate into the user data and send it */
|
||||||
|
|
||||||
|
memcpy(pstate->rf_buffer, uip_appdata, recvlen);
|
||||||
|
|
||||||
|
/* Don't allow any further call backs. */
|
||||||
|
|
||||||
|
uip_conn->private = NULL;
|
||||||
|
uip_conn->callback = NULL;
|
||||||
|
|
||||||
|
/* Wake up the waiting thread, returning the number of bytes
|
||||||
|
* actually read.
|
||||||
|
*/
|
||||||
|
|
||||||
|
pstate->rf_buflen = recvlen;
|
||||||
|
sem_post(&pstate-> rf_sem);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Copy the appdate into the user data and send it */
|
/* No data has been received. If this is a poll event, then check
|
||||||
|
* for a timeout.
|
||||||
memcpy(pstate->rf_buffer, uip_appdata, recvlen);
|
|
||||||
|
|
||||||
/* Don't allow any further call backs. */
|
|
||||||
|
|
||||||
uip_conn->private = NULL;
|
|
||||||
uip_conn->callback = NULL;
|
|
||||||
|
|
||||||
/* Wake up the waiting thread, returning the number of bytes
|
|
||||||
* actually read.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
pstate->rf_buflen = recvlen;
|
#if defined(CONFIG_NET_SOCKOPTS) && !defined(CONFIG_DISABLE_CLOCK)
|
||||||
sem_post(&pstate-> rf_sem);
|
else if (uip_newdata() && pstate->rf_sock)
|
||||||
|
{
|
||||||
|
/* Check if SO_RCVTIMEO has been selected for this socket */
|
||||||
|
|
||||||
|
uint rcvtimeo = ;
|
||||||
|
if (pstate->rf_sock->s_rcvtimeo)
|
||||||
|
{
|
||||||
|
/* Yes.. Check if the timeout has elapsed */
|
||||||
|
|
||||||
|
if (net_timeo(pstate->rf_starttime, pstate->rf_sock->s_rcvtimeo))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -213,6 +242,12 @@ ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *
|
|||||||
state. rf_buflen = len;
|
state. rf_buflen = len;
|
||||||
state. rf_buffer = buf;
|
state. rf_buffer = buf;
|
||||||
|
|
||||||
|
#if defined(CONFIG_NET_SOCKOPTS) && !defined(CONFIG_DISABLE_CLOCK)
|
||||||
|
/* Set up the start time for the timeout */
|
||||||
|
|
||||||
|
state.rf_starttime = g_system_timer;
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Setup the UDP socket */
|
/* Setup the UDP socket */
|
||||||
|
|
||||||
ret = uip_udpconnect(psock->s_conn, NULL);
|
ret = uip_udpconnect(psock->s_conn, NULL);
|
||||||
@ -244,6 +279,20 @@ ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *
|
|||||||
sem_destroy(&state. rf_sem);
|
sem_destroy(&state. rf_sem);
|
||||||
irqrestore(save);
|
irqrestore(save);
|
||||||
|
|
||||||
|
/* Check for a timeout. Errors are signaled by negative errno values
|
||||||
|
* for the rcv length
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if defined(CONFIG_NET_SOCKOPTS) && !defined(CONFIG_DISABLE_CLOCK)
|
||||||
|
if (state.rf_buflen < 0)
|
||||||
|
{
|
||||||
|
/* Return EGAIN on a timeout */
|
||||||
|
|
||||||
|
err = -state.rf_buflen;
|
||||||
|
goto errout;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* If sem_wait failed, then we were probably reawakened by a signal. In
|
/* If sem_wait failed, then we were probably reawakened by a signal. In
|
||||||
* this case, sem_wait will have set errno appropriately.
|
* this case, sem_wait will have set errno appropriately.
|
||||||
*/
|
*/
|
||||||
@ -253,8 +302,9 @@ ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *
|
|||||||
return ERROR;
|
return ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
return state.rf_buflen;
|
|
||||||
#warning "Needs to return server address"
|
#warning "Needs to return server address"
|
||||||
|
return state.rf_buflen;
|
||||||
|
|
||||||
#else
|
#else
|
||||||
err = ENOSYS;
|
err = ENOSYS;
|
||||||
#endif
|
#endif
|
||||||
|
@ -58,9 +58,9 @@
|
|||||||
|
|
||||||
struct sendto_s
|
struct sendto_s
|
||||||
{
|
{
|
||||||
sem_t st_sem;
|
sem_t st_sem; /* Semaphore signals sendto completion */
|
||||||
uint16 st_buflen;
|
uint16 st_buflen; /* Length of send buffer (error if <0) */
|
||||||
const char *st_buffer;
|
const char *st_buffer; /* Pointer to send buffer */
|
||||||
};
|
};
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
|
@ -39,7 +39,6 @@
|
|||||||
|
|
||||||
#include <nuttx/config.h>
|
#include <nuttx/config.h>
|
||||||
#include <semaphore.h>
|
#include <semaphore.h>
|
||||||
#include <wdog.h>
|
|
||||||
#include <arch/irq.h>
|
#include <arch/irq.h>
|
||||||
#include <net/uip/uip.h>
|
#include <net/uip/uip.h>
|
||||||
|
|
||||||
@ -63,31 +62,18 @@ static uint16 uip_waitflags = 0; /* UIP flags to wait for */
|
|||||||
* Private Functions
|
* Private Functions
|
||||||
************************************************************/
|
************************************************************/
|
||||||
|
|
||||||
/* Called from the timer interrupt handler when a event wait
|
|
||||||
* watchdog expires.
|
|
||||||
*/
|
|
||||||
|
|
||||||
static void uip_event_timeout(int argc, uint32 itcb, ...)
|
|
||||||
{
|
|
||||||
irqstate_t save = irqsave(); /* Should not be necessary */
|
|
||||||
uip_flags |= UIP_APPTIMEOUT; /* Set software timeout event */
|
|
||||||
uip_event_signal(); /* Signal the waiting thread/task */
|
|
||||||
irqrestore(save); /* Restore interrupts */
|
|
||||||
}
|
|
||||||
|
|
||||||
/************************************************************
|
/************************************************************
|
||||||
* Global Functions
|
* Global Functions
|
||||||
************************************************************/
|
************************************************************/
|
||||||
|
|
||||||
/* This function is called user code to set up the wait */
|
/* This function is called user code to set up the wait */
|
||||||
|
|
||||||
int uip_event_timedwait(uint16 waitflags, int timeout)
|
int uip_event_wait(uint16 waitflags)
|
||||||
{
|
{
|
||||||
/* Prevent conflicts with the interrupt level operation of
|
/* Prevent conflicts with the interrupt level operation of
|
||||||
* uip_event_signal().
|
* uip_event_signal().
|
||||||
*/
|
*/
|
||||||
irqstate_t save = irqsave();
|
irqstate_t save = irqsave();
|
||||||
WDOG_ID wdog;
|
|
||||||
|
|
||||||
/* At present, we support only a single waiter. If uip_waitflags
|
/* At present, we support only a single waiter. If uip_waitflags
|
||||||
* is non-zero on entry, then there is a problem.
|
* is non-zero on entry, then there is a problem.
|
||||||
@ -111,52 +97,17 @@ int uip_event_timedwait(uint16 waitflags, int timeout)
|
|||||||
|
|
||||||
uip_waitflags = waitflags;
|
uip_waitflags = waitflags;
|
||||||
|
|
||||||
/* Was a timeut requested as well? */
|
/* Wait for the event to occur */
|
||||||
|
|
||||||
if (timeout)
|
|
||||||
{
|
|
||||||
/* Yes, then set the application timeout event as well */
|
|
||||||
|
|
||||||
uip_waitflags |= UIP_APPTIMEOUT;
|
|
||||||
|
|
||||||
/* Create a watchdog */
|
|
||||||
|
|
||||||
wdog = wd_create();
|
|
||||||
if (!wdog)
|
|
||||||
{
|
|
||||||
goto errout_with_irqdisabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Start the watchdog */
|
|
||||||
|
|
||||||
wd_start(wdog, timeout, (wdentry_t)uip_event_timeout, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Wait for the event (or timeout) to occur */
|
|
||||||
|
|
||||||
if (sem_wait(&uip_waitsem) != 0)
|
if (sem_wait(&uip_waitsem) != 0)
|
||||||
{
|
{
|
||||||
goto errout_with_watchdog;
|
goto errout_with_irqdisabled;
|
||||||
}
|
|
||||||
|
|
||||||
/* We no longer need the watchdog */
|
|
||||||
|
|
||||||
if (wdog)
|
|
||||||
{
|
|
||||||
wd_delete(wdog);
|
|
||||||
wdog = NULL;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
irqrestore(save);
|
irqrestore(save);
|
||||||
return OK;
|
return OK;
|
||||||
|
|
||||||
errout_with_watchdog:
|
|
||||||
if (wdog)
|
|
||||||
{
|
|
||||||
wd_delete(wdog);
|
|
||||||
}
|
|
||||||
|
|
||||||
errout_with_irqdisabled:
|
errout_with_irqdisabled:
|
||||||
irqrestore(save);
|
irqrestore(save);
|
||||||
return ERROR;
|
return ERROR;
|
||||||
|
@ -43,13 +43,14 @@
|
|||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <pthread.h>
|
#include <unistd.h>
|
||||||
#include <semaphore.h>
|
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
#include <errno.h>
|
||||||
#include <debug.h>
|
#include <debug.h>
|
||||||
#include <sys/socket.h>
|
|
||||||
|
|
||||||
#include <net/uip/uip.h>
|
#include <net/uip/uip.h>
|
||||||
#include <net/uip/dhcpc.h>
|
#include <net/uip/dhcpc.h>
|
||||||
@ -58,10 +59,6 @@
|
|||||||
* Definitions
|
* Definitions
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
/* CLK_TCK is the frequency of the system clock (typically 100Hz) */
|
|
||||||
|
|
||||||
#define CLOCK_SECOND CLK_TCK
|
|
||||||
|
|
||||||
#define STATE_INITIAL 0
|
#define STATE_INITIAL 0
|
||||||
#define STATE_SENDING 1
|
#define STATE_SENDING 1
|
||||||
#define STATE_OFFER_RECEIVED 2
|
#define STATE_OFFER_RECEIVED 2
|
||||||
@ -96,6 +93,8 @@
|
|||||||
#define DHCP_OPTION_REQ_LIST 55
|
#define DHCP_OPTION_REQ_LIST 55
|
||||||
#define DHCP_OPTION_END 255
|
#define DHCP_OPTION_END 255
|
||||||
|
|
||||||
|
#define BUFFER_SIZE 256
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Private Types
|
* Private Types
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
@ -103,12 +102,10 @@
|
|||||||
struct dhcpc_state_internal
|
struct dhcpc_state_internal
|
||||||
{
|
{
|
||||||
struct uip_udp_conn *conn;
|
struct uip_udp_conn *conn;
|
||||||
struct dhcpc_state *result;
|
|
||||||
const void *mac_addr;
|
const void *mac_addr;
|
||||||
int mac_len;
|
int mac_len;
|
||||||
int sockfd;
|
int sockfd;
|
||||||
uint16 ticks;
|
char buffer[256];
|
||||||
char state;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct dhcp_msg
|
struct dhcp_msg
|
||||||
@ -183,28 +180,28 @@ static uint8 *add_end(uint8 *optptr)
|
|||||||
return optptr;
|
return optptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void create_msg(struct dhcpc_state_internal *pdhcpc, struct dhcp_msg *m)
|
static void create_msg(struct dhcpc_state_internal *pdhcpc, struct dhcp_msg *pmsg)
|
||||||
{
|
{
|
||||||
m->op = DHCP_REQUEST;
|
pmsg->op = DHCP_REQUEST;
|
||||||
m->htype = DHCP_HTYPE_ETHERNET;
|
pmsg->htype = DHCP_HTYPE_ETHERNET;
|
||||||
m->hlen = pdhcpc->mac_len;
|
pmsg->hlen = pdhcpc->mac_len;
|
||||||
m->hops = 0;
|
pmsg->hops = 0;
|
||||||
memcpy(m->xid, xid, sizeof(m->xid));
|
memcpy(pmsg->xid, xid, sizeof(pmsg->xid));
|
||||||
m->secs = 0;
|
pmsg->secs = 0;
|
||||||
m->flags = HTONS(BOOTP_BROADCAST); /* Broadcast bit. */
|
pmsg->flags = HTONS(BOOTP_BROADCAST); /* Broadcast bit. */
|
||||||
/* uip_ipaddr_copy(m->ciaddr, uip_hostaddr);*/
|
/* uip_ipaddr_copy(pmsg->ciaddr, uip_hostaddr);*/
|
||||||
memcpy(m->ciaddr, uip_hostaddr, sizeof(m->ciaddr));
|
memcpy(pmsg->ciaddr, uip_hostaddr, sizeof(pmsg->ciaddr));
|
||||||
memset(m->yiaddr, 0, sizeof(m->yiaddr));
|
memset(pmsg->yiaddr, 0, sizeof(pmsg->yiaddr));
|
||||||
memset(m->siaddr, 0, sizeof(m->siaddr));
|
memset(pmsg->siaddr, 0, sizeof(pmsg->siaddr));
|
||||||
memset(m->giaddr, 0, sizeof(m->giaddr));
|
memset(pmsg->giaddr, 0, sizeof(pmsg->giaddr));
|
||||||
memcpy(m->chaddr, pdhcpc->mac_addr, pdhcpc->mac_len);
|
memcpy(pmsg->chaddr, pdhcpc->mac_addr, pdhcpc->mac_len);
|
||||||
memset(&m->chaddr[pdhcpc->mac_len], 0, sizeof(m->chaddr) - pdhcpc->mac_len);
|
memset(&pmsg->chaddr[pdhcpc->mac_len], 0, sizeof(pmsg->chaddr) - pdhcpc->mac_len);
|
||||||
#ifndef CONFIG_NET_DHCP_LIGHT
|
#ifndef CONFIG_NET_DHCP_LIGHT
|
||||||
memset(m->sname, 0, sizeof(m->sname));
|
memset(pmsg->sname, 0, sizeof(pmsg->sname));
|
||||||
memset(m->file, 0, sizeof(m->file));
|
memset(pmsg->file, 0, sizeof(pmsg->file));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
memcpy(m->options, magic_cookie, sizeof(magic_cookie));
|
memcpy(pmsg->options, magic_cookie, sizeof(magic_cookie));
|
||||||
}
|
}
|
||||||
|
|
||||||
static int send_discover(struct dhcpc_state_internal *pdhcpc)
|
static int send_discover(struct dhcpc_state_internal *pdhcpc)
|
||||||
@ -228,7 +225,7 @@ static int send_discover(struct dhcpc_state_internal *pdhcpc)
|
|||||||
(struct sockaddr*)&addr, sizeof(struct sockaddr_in));
|
(struct sockaddr*)&addr, sizeof(struct sockaddr_in));
|
||||||
}
|
}
|
||||||
|
|
||||||
static int send_request(struct dhcpc_state_internal *pdhcpc)
|
static int send_request(struct dhcpc_state_internal *pdhcpc, struct dhcpc_state *presult)
|
||||||
{
|
{
|
||||||
struct dhcp_msg msg;
|
struct dhcp_msg msg;
|
||||||
struct sockaddr_in addr;
|
struct sockaddr_in addr;
|
||||||
@ -237,8 +234,8 @@ static int send_request(struct dhcpc_state_internal *pdhcpc)
|
|||||||
|
|
||||||
create_msg(pdhcpc, &msg);
|
create_msg(pdhcpc, &msg);
|
||||||
pend = add_msg_type(&msg.options[4], DHCPREQUEST);
|
pend = add_msg_type(&msg.options[4], DHCPREQUEST);
|
||||||
pend = add_server_id(pdhcpc->result, pend);
|
pend = add_server_id(presult, pend);
|
||||||
pend = add_req_ipaddr(pdhcpc->result, pend);
|
pend = add_req_ipaddr(presult, pend);
|
||||||
pend = add_end(pend);
|
pend = add_end(pend);
|
||||||
len = pend - (uint8*)&msg;
|
len = pend - (uint8*)&msg;
|
||||||
|
|
||||||
@ -286,87 +283,156 @@ static uint8 parse_options(struct dhcpc_state *presult, uint8 *optptr, int len)
|
|||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint8 parse_msg(struct dhcpc_state_internal *pdhcpc)
|
static uint8 parse_msg(struct dhcpc_state_internal *pdhcpc, int buflen, struct dhcpc_state *presult)
|
||||||
{
|
{
|
||||||
struct dhcpc_state *presult = pdhcpc->result;
|
struct dhcp_msg *pbuffer = (struct dhcp_msg *)pdhcpc->buffer;
|
||||||
struct dhcp_msg *m = (struct dhcp_msg *)uip_appdata;
|
|
||||||
|
|
||||||
if (m->op == DHCP_REPLY &&
|
if (pbuffer->op == DHCP_REPLY &&
|
||||||
memcmp(m->xid, xid, sizeof(xid)) == 0 &&
|
memcmp(pbuffer->xid, xid, sizeof(xid)) == 0 &&
|
||||||
memcmp(m->chaddr, pdhcpc->mac_addr, pdhcpc->mac_len) == 0)
|
memcmp(pbuffer->chaddr, pdhcpc->mac_addr, pdhcpc->mac_len) == 0)
|
||||||
{
|
{
|
||||||
memcpy(presult->ipaddr, m->yiaddr, 4);
|
memcpy(presult->ipaddr, pbuffer->yiaddr, 4);
|
||||||
return parse_options(presult, &m->options[4], uip_datalen());
|
return parse_options(presult, &pbuffer->options[4], buflen);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int handle_dhcp(struct dhcpc_state_internal *pdhcpc)
|
/****************************************************************************
|
||||||
|
* Global Functions
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
void *dhcpc_open(const void *mac_addr, int mac_len)
|
||||||
{
|
{
|
||||||
struct dhcpc_state *presult = pdhcpc->result;
|
struct dhcpc_state_internal *pdhcpc;
|
||||||
|
struct sockaddr_in addr;
|
||||||
|
struct timeval tv;
|
||||||
|
|
||||||
restart:
|
/* Allocate an internal DHCP structure */
|
||||||
pdhcpc->state = STATE_SENDING;
|
|
||||||
pdhcpc->ticks = CLOCK_SECOND;
|
pdhcpc = (struct dhcpc_state_internal *)malloc(sizeof(struct dhcpc_state_internal));
|
||||||
|
if (pdhcpc)
|
||||||
|
{
|
||||||
|
/* Initialize the allocated structure */
|
||||||
|
|
||||||
|
memset(pdhcpc, 0, sizeof(struct dhcpc_state_internal));
|
||||||
|
pdhcpc->mac_addr = mac_addr;
|
||||||
|
pdhcpc->mac_len = mac_len;
|
||||||
|
|
||||||
|
/* Create a UDP socket */
|
||||||
|
|
||||||
|
pdhcpc->sockfd = socket(PF_INET, SOCK_DGRAM, 0);
|
||||||
|
if (pdhcpc->sockfd < 0)
|
||||||
|
{
|
||||||
|
free(pdhcpc);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* bind the socket */
|
||||||
|
|
||||||
|
addr.sin_family = AF_INET;
|
||||||
|
addr.sin_port = HTONS(DHCPC_CLIENT_PORT);
|
||||||
|
addr.sin_addr.s_addr = INADDR_ANY;
|
||||||
|
|
||||||
|
if (bind(pdhcpc->sockfd, (struct sockaddr*)&addr, sizeof(struct sockaddr_in)) < 0)
|
||||||
|
{
|
||||||
|
close(pdhcpc->sockfd);
|
||||||
|
free(pdhcpc);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Configure for read timeouts */
|
||||||
|
|
||||||
|
tv.tv_sec = 30;
|
||||||
|
tv.tv_usec = 0;
|
||||||
|
if (setsockopt(pdhcpc->sockfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(struct timeval)) < 0)
|
||||||
|
{
|
||||||
|
close(pdhcpc->sockfd);
|
||||||
|
free(pdhcpc);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (void*)pdhcpc;
|
||||||
|
}
|
||||||
|
|
||||||
|
void dhcpc_close(void *handle)
|
||||||
|
{
|
||||||
|
struct dchcpc_state_internal *pdhcpc = (struct dchcpc_state_internal *)handle;
|
||||||
|
if (pdhcpc)
|
||||||
|
{
|
||||||
|
free(pdhcpc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int dhcpc_request(void *handle, struct dhcpc_state *presult)
|
||||||
|
{
|
||||||
|
struct dhcpc_state_internal *pdhcpc = (struct dhcpc_state_internal *)handle;
|
||||||
|
ssize_t result;
|
||||||
|
int state;
|
||||||
|
|
||||||
|
/* Loop until we receive the offer */
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
/* Send the command */
|
state = STATE_SENDING;
|
||||||
|
|
||||||
send_discover(pdhcpc);
|
do
|
||||||
|
|
||||||
/* Set up a watchdog to timeout the recvfrom */
|
|
||||||
#warning need to implement timeout;
|
|
||||||
|
|
||||||
/* Wait for the response */
|
|
||||||
#warning need to use recvfrom
|
|
||||||
uip_event_timedwait(UIP_NEWDATA, CLOCK_SECOND);
|
|
||||||
|
|
||||||
if (uip_newdata() && parse_msg(pdhcpc) == DHCPOFFER)
|
|
||||||
{
|
{
|
||||||
pdhcpc->state = STATE_OFFER_RECEIVED;
|
/* Send the command */
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pdhcpc->ticks < CLOCK_SECOND * 60)
|
if (send_discover(pdhcpc) < 0)
|
||||||
{
|
{
|
||||||
pdhcpc->ticks *= 2;
|
return ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get the response */
|
||||||
|
|
||||||
|
result = recv(pdhcpc->sockfd, pdhcpc->buffer, BUFFER_SIZE, 0);
|
||||||
|
if (result >= 0)
|
||||||
|
{
|
||||||
|
if (parse_msg(pdhcpc, result, presult) == DHCPOFFER)
|
||||||
|
{
|
||||||
|
state = STATE_OFFER_RECEIVED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (*get_errno_ptr() != EAGAIN)
|
||||||
|
{
|
||||||
|
/* An error other than a timeout was received */
|
||||||
|
|
||||||
|
return ERROR;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
while (state != STATE_OFFER_RECEIVED);
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
/* Send the request */
|
||||||
|
|
||||||
|
if (send_request(pdhcpc, presult) < 0)
|
||||||
|
{
|
||||||
|
return ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get the response */
|
||||||
|
|
||||||
|
result = recv(pdhcpc->sockfd, pdhcpc->buffer, BUFFER_SIZE, 0);
|
||||||
|
if (result >= 0)
|
||||||
|
{
|
||||||
|
if (parse_msg(pdhcpc, result, presult) == DHCPACK)
|
||||||
|
{
|
||||||
|
state = STATE_CONFIG_RECEIVED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (*get_errno_ptr() != EAGAIN)
|
||||||
|
{
|
||||||
|
/* An error other than a timeout was received */
|
||||||
|
|
||||||
|
return ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (state != STATE_CONFIG_RECEIVED);
|
||||||
}
|
}
|
||||||
while(pdhcpc->state != STATE_OFFER_RECEIVED);
|
while(state != STATE_CONFIG_RECEIVED);
|
||||||
|
|
||||||
pdhcpc->ticks = CLOCK_SECOND;
|
|
||||||
|
|
||||||
do
|
|
||||||
{
|
|
||||||
/* Send the request */
|
|
||||||
|
|
||||||
send_request(pdhcpc);
|
|
||||||
|
|
||||||
/* Set up a watchdog to timeout the recvfrom */
|
|
||||||
#warning need to implement timeout;
|
|
||||||
|
|
||||||
/* Then wait to received the response */
|
|
||||||
#warning need to use recvfrom
|
|
||||||
|
|
||||||
uip_event_timedwait(UIP_NEWDATA, CLOCK_SECOND);
|
|
||||||
|
|
||||||
if (uip_newdata() && parse_msg(pdhcpc) == DHCPACK)
|
|
||||||
{
|
|
||||||
pdhcpc->state = STATE_CONFIG_RECEIVED;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pdhcpc->ticks <= CLOCK_SECOND * 10)
|
|
||||||
{
|
|
||||||
pdhcpc->ticks += CLOCK_SECOND;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
goto restart;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
while(pdhcpc->state != STATE_CONFIG_RECEIVED);
|
|
||||||
|
|
||||||
dbg("Got IP address %d.%d.%d.%d\n",
|
dbg("Got IP address %d.%d.%d.%d\n",
|
||||||
uip_ipaddr1(presult->ipaddr), uip_ipaddr2(presult->ipaddr),
|
uip_ipaddr1(presult->ipaddr), uip_ipaddr2(presult->ipaddr),
|
||||||
@ -384,74 +450,3 @@ restart:
|
|||||||
ntohs(presult->lease_time[0])*65536ul + ntohs(presult->lease_time[1]));
|
ntohs(presult->lease_time[0])*65536ul + ntohs(presult->lease_time[1]));
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************
|
|
||||||
* Global Functions
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
void *dhcpc_open(const void *mac_addr, int mac_len)
|
|
||||||
{
|
|
||||||
struct dhcpc_state_internal *pdhcpc;
|
|
||||||
struct sockaddr_in addr;
|
|
||||||
|
|
||||||
/* Allocate an internal DHCP structure */
|
|
||||||
|
|
||||||
pdhcpc = (struct dhcpc_state_internal *)malloc(sizeof(struct dhcpc_state_internal));
|
|
||||||
if (pdhcpc)
|
|
||||||
{
|
|
||||||
/* Initialize the allocated structure */
|
|
||||||
|
|
||||||
memset(pdhcpc, 0, sizeof(struct dhcpc_state_internal));
|
|
||||||
pdhcpc->mac_addr = mac_addr;
|
|
||||||
pdhcpc->mac_len = mac_len;
|
|
||||||
pdhcpc->state = STATE_INITIAL;
|
|
||||||
|
|
||||||
/* Create a UDP socket */
|
|
||||||
|
|
||||||
pdhcpc->sockfd = socket(PF_INET, SOCK_DGRAM, 0);
|
|
||||||
if (pdhcpc->sockfd < 0)
|
|
||||||
{
|
|
||||||
free(pdhcpc);
|
|
||||||
pdhcpc = NULL;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* bind the socket */
|
|
||||||
|
|
||||||
addr.sin_family = AF_INET;
|
|
||||||
addr.sin_port = HTONS(DHCPC_CLIENT_PORT);
|
|
||||||
addr.sin_addr.s_addr = INADDR_ANY;
|
|
||||||
|
|
||||||
if (bind(pdhcpc->sockfd, &addr, sizeof(struct sockaddr_in)) < 0)
|
|
||||||
{
|
|
||||||
free(pdhcpc);
|
|
||||||
pdhcpc = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return (void*)pdhcpc;
|
|
||||||
}
|
|
||||||
|
|
||||||
void dhcpc_close(void *handle)
|
|
||||||
{
|
|
||||||
struct dchcpc_state_internal *pdhcpc = (struct dchcpc_state_internal *)handle;
|
|
||||||
if (pdhcpc)
|
|
||||||
{
|
|
||||||
free(pdhcpc);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int dhcpc_request(void *handle, struct dhcpc_state *ds)
|
|
||||||
{
|
|
||||||
struct dhcpc_state_internal *pdhcpc = (struct dhcpc_state_internal *)handle;
|
|
||||||
uint16 ipaddr[2];
|
|
||||||
|
|
||||||
if (pdhcpc->state == STATE_INITIAL)
|
|
||||||
{
|
|
||||||
uip_ipaddr(ipaddr, 0,0,0,0);
|
|
||||||
uip_sethostaddr(ipaddr);
|
|
||||||
}
|
|
||||||
|
|
||||||
pdhcpc->result = ds;
|
|
||||||
return handle_dhcp(pdhcpc);
|
|
||||||
}
|
|
||||||
|
@ -52,6 +52,9 @@
|
|||||||
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <errno.h>
|
||||||
#include <debug.h>
|
#include <debug.h>
|
||||||
|
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
@ -341,10 +344,29 @@ int resolv_query(const char *name, struct sockaddr_in6 *addr)
|
|||||||
int resolv_query(const char *name, struct sockaddr_in *addr)
|
int resolv_query(const char *name, struct sockaddr_in *addr)
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
int ret = send_query(name, addr);
|
int retries;
|
||||||
if (ret == 0)
|
int ret;
|
||||||
|
|
||||||
|
// Loop while receive timeout errors occur and there are remaining retries
|
||||||
|
for (retries = 0; retries < 3; retries++)
|
||||||
{
|
{
|
||||||
|
if (send_query(name, addr) < 0)
|
||||||
|
{
|
||||||
|
return ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
ret = recv_response(addr);
|
ret = recv_response(addr);
|
||||||
|
if (ret >= 0)
|
||||||
|
{
|
||||||
|
/* Response received successfully */
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (*get_errno_ptr() != EAGAIN)
|
||||||
|
{
|
||||||
|
/* Some failure other than receive timeout occurred */
|
||||||
|
return ERROR;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -352,9 +374,9 @@ int resolv_query(const char *name, struct sockaddr_in *addr)
|
|||||||
/* Obtain the currently configured DNS server. */
|
/* Obtain the currently configured DNS server. */
|
||||||
|
|
||||||
#ifdef CONFIG_NET_IPv6
|
#ifdef CONFIG_NET_IPv6
|
||||||
void resolv_getserver(const struct sockaddr_in6 *dnsserver)
|
void resolv_getserver(struct sockaddr_in6 *dnsserver)
|
||||||
#else
|
#else
|
||||||
void resolv_getserver(const struct sockaddr_in *dnsserver)
|
void resolv_getserver(struct sockaddr_in *dnsserver)
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
memcpy(dnsserver, &g_dnsserver, ADDRLEN);
|
memcpy(dnsserver, &g_dnsserver, ADDRLEN);
|
||||||
@ -375,10 +397,23 @@ void resolv_conf(const struct sockaddr_in *dnsserver)
|
|||||||
|
|
||||||
int resolv_init(void)
|
int resolv_init(void)
|
||||||
{
|
{
|
||||||
|
struct timeval tv;
|
||||||
g_sockfd = socket(PF_INET, SOCK_DGRAM, 0);
|
g_sockfd = socket(PF_INET, SOCK_DGRAM, 0);
|
||||||
if (g_sockfd < 0)
|
if (g_sockfd < 0)
|
||||||
{
|
{
|
||||||
return ERROR;
|
return ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Set up a receive timeout */
|
||||||
|
|
||||||
|
tv.tv_sec = 30;
|
||||||
|
tv.tv_usec = 0;
|
||||||
|
if (setsockopt(g_sockfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(struct timeval)) < 0)
|
||||||
|
{
|
||||||
|
close(g_sockfd);
|
||||||
|
g_sockfd = -1;
|
||||||
|
return ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user