From e0fc53b23c8ff1c4390456e54d2fcf98a703f671 Mon Sep 17 00:00:00 2001 From: songlinzhang Date: Mon, 11 Oct 2021 15:43:26 +0800 Subject: [PATCH] netutils/dhcpc: add non-blocking interface Signed-off-by: songlinzhang --- include/netutils/dhcpc.h | 4 ++ netutils/dhcpc/dhcpc.c | 152 ++++++++++++++++++++++++++++++++++++--- 2 files changed, 145 insertions(+), 11 deletions(-) diff --git a/include/netutils/dhcpc.h b/include/netutils/dhcpc.h index b0fb5a1b2..8ec670723 100644 --- a/include/netutils/dhcpc.h +++ b/include/netutils/dhcpc.h @@ -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 diff --git a/netutils/dhcpc/dhcpc.c b/netutils/dhcpc/dhcpc.c index 008f16a52..2ff771bfd 100644 --- a/netutils/dhcpc/dhcpc.c +++ b/netutils/dhcpc/dhcpc.c @@ -52,6 +52,7 @@ #include #include #include +#include #include #include @@ -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->interface = interface; + 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; +}