netutils/dhcpc: add non-blocking interface

Signed-off-by: songlinzhang <songlinzhang@xiaomi.com>
This commit is contained in:
songlinzhang 2021-10-11 15:43:26 +08:00 committed by Xiang Xiao
parent c9f736005a
commit e0fc53b23c
2 changed files with 145 additions and 11 deletions

View File

@ -63,6 +63,8 @@ struct dhcpc_state
uint32_t lease_time; /* Lease expires in this number of seconds */
};
typedef void (*dhcpc_callback_t)(FAR struct dhcpc_state *presult);
/****************************************************************************
* Public Function Prototypes
****************************************************************************/
@ -78,6 +80,8 @@ extern "C"
FAR void *dhcpc_open(FAR const char *interface,
FAR const void *mac_addr, int mac_len);
int dhcpc_request(FAR void *handle, FAR struct dhcpc_state *presult);
int dhcpc_request_async(FAR void *handle, dhcpc_callback_t callback);
void dhcpc_cancel(FAR void *handle);
void dhcpc_close(FAR void *handle);
#undef EXTERN

View File

@ -52,6 +52,7 @@
#include <unistd.h>
#include <errno.h>
#include <debug.h>
#include <pthread.h>
#include <arpa/inet.h>
#include <netinet/udp.h>
@ -129,12 +130,15 @@ struct dhcp_msg
struct dhcpc_state_s
{
FAR const char *interface;
FAR const void *ds_macaddr;
int ds_maclen;
int sockfd;
struct in_addr ipaddr;
struct in_addr serverid;
struct dhcp_msg packet;
bool cancel;
pthread_t thread; /* Thread ID of the DHCPC thread */
dhcpc_callback_t callback; /* Thread callback of the DHCPC thread */
int maclen;
uint8_t macaddr[1];
};
/****************************************************************************
@ -229,11 +233,10 @@ static int dhcpc_sendmsg(FAR struct dhcpc_state_s *pdhcpc,
memset(&pdhcpc->packet, 0, sizeof(struct dhcp_msg));
pdhcpc->packet.op = DHCP_REQUEST;
pdhcpc->packet.htype = DHCP_HTYPE_ETHERNET;
pdhcpc->packet.hlen = pdhcpc->ds_maclen;
pdhcpc->packet.hlen = pdhcpc->maclen;
memcpy(pdhcpc->packet.xid, xid, 4);
memcpy(pdhcpc->packet.chaddr, pdhcpc->ds_macaddr, pdhcpc->ds_maclen);
memset(&pdhcpc->packet.chaddr[pdhcpc->ds_maclen],
0, 16 - pdhcpc->ds_maclen);
memcpy(pdhcpc->packet.chaddr, pdhcpc->macaddr, pdhcpc->maclen);
memset(&pdhcpc->packet.chaddr[pdhcpc->maclen], 0, 16 - pdhcpc->maclen);
memcpy(pdhcpc->packet.options, magic_cookie, sizeof(magic_cookie));
/* Add the common header options */
@ -434,7 +437,7 @@ static uint8_t dhcpc_parsemsg(FAR struct dhcpc_state_s *pdhcpc, int buflen,
if (buflen >= 44 && pdhcpc->packet.op == DHCP_REPLY &&
memcmp(pdhcpc->packet.xid, xid, sizeof(xid)) == 0 &&
memcmp(pdhcpc->packet.chaddr,
pdhcpc->ds_macaddr, pdhcpc->ds_maclen) == 0)
pdhcpc->macaddr, pdhcpc->maclen) == 0)
{
memcpy(&presult->ipaddr.s_addr, pdhcpc->packet.yiaddr, 4);
return dhcpc_parseoptions(presult, &pdhcpc->packet.options[4],
@ -445,6 +448,47 @@ static uint8_t dhcpc_parsemsg(FAR struct dhcpc_state_s *pdhcpc, int buflen,
return 0;
}
/****************************************************************************
* Name: dhcpc_run
****************************************************************************/
static void *dhcpc_run(void *args)
{
FAR struct dhcpc_state_s *pdhcpc = (FAR struct dhcpc_state_s *)args;
struct dhcpc_state result;
int ret;
while (1)
{
ret = dhcpc_request(pdhcpc, &result);
if (ret == OK)
{
pdhcpc->callback(&result);
}
else
{
pdhcpc->callback(NULL);
nerr("dhcpc_request error\n");
}
if (pdhcpc->cancel)
{
return NULL;
}
while (result.lease_time)
{
result.lease_time = sleep(result.lease_time);
if (pdhcpc->cancel)
{
return NULL;
}
}
}
return NULL;
}
/****************************************************************************
* Public Functions
****************************************************************************/
@ -468,15 +512,15 @@ FAR void *dhcpc_open(FAR const char *interface, FAR const void *macaddr,
/* Allocate an internal DHCP structure */
pdhcpc = (FAR struct dhcpc_state_s *)malloc(sizeof(struct dhcpc_state_s));
pdhcpc = malloc(sizeof(struct dhcpc_state_s) + maclen - 1);
if (pdhcpc)
{
/* Initialize the allocated structure */
memset(pdhcpc, 0, sizeof(struct dhcpc_state_s));
pdhcpc->interface = interface;
pdhcpc->ds_macaddr = macaddr;
pdhcpc->ds_maclen = maclen;
pdhcpc->maclen = maclen;
memcpy(pdhcpc->macaddr, macaddr, pdhcpc->maclen);
/* Create a UDP socket */
@ -551,6 +595,11 @@ void dhcpc_close(FAR void *handle)
if (pdhcpc)
{
if (pdhcpc->thread)
{
dhcpc_cancel(pdhcpc);
}
if (pdhcpc->sockfd)
{
close(pdhcpc->sockfd);
@ -560,6 +609,46 @@ void dhcpc_close(FAR void *handle)
}
}
/****************************************************************************
* Name: dhcpc_cancel
****************************************************************************/
void dhcpc_cancel(FAR void *handle)
{
struct dhcpc_state_s *pdhcpc = (struct dhcpc_state_s *)handle;
sighandler_t old;
int ret;
if (pdhcpc)
{
pdhcpc->cancel = true;
if (pdhcpc->thread)
{
old = signal(SIGQUIT, SIG_IGN);
/* Signal the dhcpc_run */
ret = pthread_kill(pdhcpc->thread, SIGQUIT);
if (ret != 0)
{
nerr("ERROR: pthread_kill DHCPC thread\n");
}
/* Wait for the end of dhcpc_run */
ret = pthread_join(pdhcpc->thread, NULL);
if (ret != 0)
{
nerr("ERROR: pthread_join DHCPC thread\n");
}
pdhcpc->thread = 0;
signal(SIGQUIT, old);
}
}
}
/****************************************************************************
* Name: dhcpc_request
****************************************************************************/
@ -599,6 +688,11 @@ int dhcpc_request(FAR void *handle, FAR struct dhcpc_state *presult)
state = STATE_INITIAL;
do
{
if (pdhcpc->cancel)
{
return ERROR;
}
/* Send the DISCOVER command */
ninfo("Broadcast DISCOVER\n");
@ -666,6 +760,11 @@ int dhcpc_request(FAR void *handle, FAR struct dhcpc_state *presult)
retries = 0;
do
{
if (pdhcpc->cancel)
{
return ERROR;
}
/* Send the REQUEST message to obtain the lease that was offered to
* us.
*/
@ -775,3 +874,34 @@ int dhcpc_request(FAR void *handle, FAR struct dhcpc_state *presult)
ninfo("Lease expires in %" PRId32 " seconds\n", presult->lease_time);
return OK;
}
/****************************************************************************
* Name: dhcpc_request_async
****************************************************************************/
int dhcpc_request_async(FAR void *handle, dhcpc_callback_t callback)
{
FAR struct dhcpc_state_s *pdhcpc = (FAR struct dhcpc_state_s *)handle;
int ret;
if (!handle || !callback)
{
return ERROR;
}
if (pdhcpc->thread)
{
nerr("ERROR: DHCPC thread already running\n");
return ERROR;
}
pdhcpc->callback = callback;
ret = pthread_create(&pdhcpc->thread, NULL, dhcpc_run, pdhcpc);
if (ret != 0)
{
nerr("ERROR: Failed to start the DHCPC thread\n");
return ERROR;
}
return OK;
}