netutils/dhcpd: cancelable dhcp daemon

Change-Id: Iea3c0b8f91b0d6d8ececcd3932d8756a9d021608
Signed-off-by: chao.an <anchao@xiaomi.com>
This commit is contained in:
chao.an 2020-05-08 14:30:04 +08:00 committed by patacongo
parent baea789137
commit 018c9420ac
9 changed files with 493 additions and 113 deletions

View File

@ -37,11 +37,13 @@
# DHCP Daemon Example
MAINSRC = target.c
CSRCS = dhcpd_daemon.c
MAINSRC = dhcpd_start.c dhcpd_stop.c target.c
# DHCPD built-in application info
PROGNAME = dhcpd
PROGNAME = dhcpd_start dhcpd_stop dhcpd
PRIORITY = SCHED_PRIORITY_DEFAULT
STACKSIZE = $(CONFIG_DEFAULT_TASK_STACKSIZE)
MODULE = $(CONFIG_EXAMPLES_DHCPD)

View File

@ -0,0 +1,152 @@
/****************************************************************************
* examples/dhcpd/dhcpd_daemon.c
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <stdint.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <net/if.h>
#include "netutils/netlib.h"
#include "netutils/dhcpd.h"
/****************************************************************************
* Preprocessor Definitions
****************************************************************************/
/* Configuration Checks *****************************************************/
/* BEWARE:
* There are other configuration settings needed in netutils/dhcpd/dhcpdc.c,
* but there are default values for those so we cannot check them here.
*/
#ifndef CONFIG_EXAMPLES_DHCPD_IPADDR
# error "You must define CONFIG_EXAMPLES_DHCPD_IPADDR"
#endif
#ifndef CONFIG_EXAMPLES_DHCPD_DRIPADDR
# error "You must define CONFIG_EXAMPLES_DHCPD_DRIPADDR"
#endif
#ifndef CONFIG_EXAMPLES_DHCPD_NETMASK
# error "You must define CONFIG_EXAMPLES_DHCPD_NETMASK"
#endif
#ifndef CONFIG_NET
# error "You must define CONFIG_NET"
#endif
#ifndef CONFIG_NET_UDP
# error "You must define CONFIG_NET_UDP"
#endif
#ifndef CONFIG_NET_BROADCAST
# error "You must define CONFIG_NET_BROADCAST"
#endif
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* dhcpd_showusage
****************************************************************************/
static void dhcpd_showusage(FAR const char *progname, int exitcode)
{
fprintf(stderr, "Usage: %s <device-name>\n", progname);
exit(exitcode);
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: dhcpd_daemon
****************************************************************************/
int dhcpd_daemon(int argc, FAR char *argv[], bool daemon)
{
FAR const char *devname;
struct in_addr addr;
#if defined(CONFIG_EXAMPLES_DHCPD_NOMAC)
uint8_t mac[IFHWADDRLEN];
#endif
/* One and only one argument is expected: The network device name. */
if (argc != 2)
{
fprintf(stderr, "ERROR: Invalid number of arguments\n");
dhcpd_showusage(argv[0], EXIT_FAILURE);
}
devname = argv[1];
/* Many embedded network interfaces must have a software assigned MAC */
#ifdef CONFIG_EXAMPLES_DHCPD_NOMAC
mac[0] = 0x00;
mac[1] = 0xe0;
mac[2] = 0xde;
mac[3] = 0xad;
mac[4] = 0xbe;
mac[5] = 0xef;
netlib_setmacaddr(devname, mac);
#endif
/* Set up our host address */
addr.s_addr = HTONL(CONFIG_EXAMPLES_DHCPD_IPADDR);
netlib_set_ipv4addr(devname, &addr);
/* Set up the default router address */
addr.s_addr = HTONL(CONFIG_EXAMPLES_DHCPD_DRIPADDR);
netlib_set_dripv4addr(devname, &addr);
/* Setup the subnet mask */
addr.s_addr = HTONL(CONFIG_EXAMPLES_DHCPD_NETMASK);
netlib_set_ipv4netmask(devname, &addr);
/* New versions of netlib_set_ipvXaddr will not bring the network up,
* So ensure the network is really up at this point.
*/
netlib_ifup(devname);
/* Then start the dhcpd */
if (daemon)
{
return dhcpd_run(devname);
}
return dhcpd_start(devname);
}

View File

@ -0,0 +1,55 @@
/****************************************************************************
* apps/examples/dhcpd/dhcpd_daemon.h
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
#ifndef __APPS_EXAMPLES_DHCPD_DHCPD_RUN_H
#define __APPS_EXAMPLES_DHCPD_DHCPD_RUN_H
/****************************************************************************
* Included Files
****************************************************************************/
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/****************************************************************************
* Public Types
****************************************************************************/
/****************************************************************************
* Public Function Prototypes
****************************************************************************/
#ifdef __cplusplus
#define EXTERN extern "C"
extern "C"
{
#else
#define EXTERN extern
#endif
int dhcpd_daemon(int argc, FAR char *argv[], bool daemon);
#undef EXTERN
#ifdef __cplusplus
}
#endif
#endif /* __APPS_EXAMPLES_DHCPD_DHCPD_RUN_H */

View File

@ -0,0 +1,42 @@
/****************************************************************************
* examples/dhcpd/dhcpd_start.c
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <stdio.h>
#include "dhcpd_daemon.h"
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: dhcpd_start_main
****************************************************************************/
int main(int argc, FAR char *argv[])
{
return dhcpd_daemon(argc, argv, false);
}

View File

@ -0,0 +1,42 @@
/****************************************************************************
* examples/dhcpd/dhcpd_stop.c
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <stdio.h>
#include "netutils/dhcpd.h"
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: dhcpd_stop_main
****************************************************************************/
int main(int argc, char **argv)
{
return dhcpd_stop();
}

View File

@ -39,63 +39,9 @@
#include <nuttx/config.h>
#include <stdint.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <net/if.h>
#include <stdio.h>
#include "netutils/netlib.h"
#include "netutils/dhcpd.h"
/****************************************************************************
* Preprocessor Definitions
****************************************************************************/
/* Configuration Checks *****************************************************/
/* BEWARE:
* There are other configuration settings needed in netutils/dhcpd/dhcpdc.c,
* but there are default values for those so we cannot check them here.
*/
#ifndef CONFIG_EXAMPLES_DHCPD_IPADDR
# error "You must define CONFIG_EXAMPLES_DHCPD_IPADDR"
#endif
#ifndef CONFIG_EXAMPLES_DHCPD_DRIPADDR
# error "You must define CONFIG_EXAMPLES_DHCPD_DRIPADDR"
#endif
#ifndef CONFIG_EXAMPLES_DHCPD_NETMASK
# error "You must define CONFIG_EXAMPLES_DHCPD_NETMASK"
#endif
#ifndef CONFIG_NET
# error "You must define CONFIG_NET"
#endif
#ifndef CONFIG_NET_UDP
# error "You must define CONFIG_NET_UDP"
#endif
#ifndef CONFIG_NET_BROADCAST
# error "You must define CONFIG_NET_BROADCAST"
#endif
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* dhcpd_showusage
****************************************************************************/
static void dhcpd_showusage(FAR const char *progname, int exitcode)
{
fprintf(stderr, "Usage: %s <device-name>\n", progname);
exit(exitcode);
}
#include "dhcpd_daemon.h"
/****************************************************************************
* Public Functions
@ -107,57 +53,5 @@ static void dhcpd_showusage(FAR const char *progname, int exitcode)
int main(int argc, FAR char *argv[])
{
FAR const char *devname;
struct in_addr addr;
#if defined(CONFIG_EXAMPLES_DHCPD_NOMAC)
uint8_t mac[IFHWADDRLEN];
#endif
/* One and only one argument is expected: The network device name. */
if (argc != 2)
{
fprintf(stderr, "ERROR: Invalid number of arguments\n");
dhcpd_showusage(argv[0], EXIT_FAILURE);
}
devname = argv[1];
/* Many embedded network interfaces must have a software assigned MAC */
#ifdef CONFIG_EXAMPLES_DHCPD_NOMAC
mac[0] = 0x00;
mac[1] = 0xe0;
mac[2] = 0xde;
mac[3] = 0xad;
mac[4] = 0xbe;
mac[5] = 0xef;
netlib_setmacaddr(devname, mac);
#endif
/* Set up our host address */
addr.s_addr = HTONL(CONFIG_EXAMPLES_DHCPD_IPADDR);
netlib_set_ipv4addr(devname, &addr);
/* Set up the default router address */
addr.s_addr = HTONL(CONFIG_EXAMPLES_DHCPD_DRIPADDR);
netlib_set_dripv4addr(devname, &addr);
/* Setup the subnet mask */
addr.s_addr = HTONL(CONFIG_EXAMPLES_DHCPD_NETMASK);
netlib_set_ipv4netmask(devname, &addr);
/* New versions of netlib_set_ipvXaddr will not bring the network up,
* So ensure the network is really up at this point.
*/
netlib_ifup(devname);
/* Then start the server */
dhcpd_run(devname);
return 0;
return dhcpd_daemon(argc, argv, true);
}

View File

@ -63,6 +63,8 @@ extern "C"
#endif
int dhcpd_run(FAR const char *interface);
int dhcpd_start(FAR const char *interface);
int dhcpd_stop(void);
#undef EXTERN
#ifdef __cplusplus

View File

@ -82,4 +82,16 @@ config NETUTILS_DHCPD_DECLINETIME
---help---
Default: 1 hour
config NETUTILS_DHCPD_PRIORITY
int "DHCPD daemon priority"
default 100
config NETUTILS_DHCPD_STACKSIZE
int "DHCPD daemon priority"
default DEFAULT_TASK_STACKSIZE
config NETUTILS_DHCPD_SIGWAKEUP
int "DHCPD wakeup signal number"
default 22
endif

View File

@ -239,6 +239,17 @@ struct dhcpmsg_s
uint8_t options[312];
};
/* This enumeration describes the state of the DHCPD daemon */
enum dhcpd_daemon_e
{
DHCPD_NOT_RUNNING = 0,
DHCPD_STARTED,
DHCPD_RUNNING,
DHCPD_STOP_REQUESTED,
DHCPD_STOPPED
};
struct dhcpd_state_s
{
/* Server configuration */
@ -266,6 +277,18 @@ struct dhcpd_state_s
struct lease_s ds_leases[CONFIG_NETUTILS_DHCPD_MAXLEASES];
};
/* This type describes the state of the DHCPD client daemon. Only one
* instance of the DHCPD daemon is permitted in this implementation.
*/
struct dhcpd_daemon_s
{
uint8_t ds_state; /* See enum dhcpd_daemon_e */
sem_t ds_lock; /* Used to protect the whole structure */
sem_t ds_sync; /* Used to synchronize start and stop events */
pid_t ds_pid; /* Task ID of the DHCPD daemon */
};
/****************************************************************************
* Private Data
****************************************************************************/
@ -277,6 +300,19 @@ static const uint8_t g_magiccookie[4] =
static struct dhcpd_state_s g_state;
/* This type describes the state of the DHCPD client daemon. Only one
* instance of the DHCPD daemon is permitted in this implementation. This
* limitation is due only to this global data structure.
*/
static struct dhcpd_daemon_s g_dhcpd_daemon =
{
DHCPD_NOT_RUNNING,
SEM_INITIALIZER(1),
SEM_INITIALIZER(0),
-1
};
/****************************************************************************
* Private Functions
****************************************************************************/
@ -1449,6 +1485,15 @@ static inline int dhcpd_openlistener(FAR const char *interface)
return sockfd;
}
/****************************************************************************
* Name: dhcpd_task_run
****************************************************************************/
static int dhcpd_task_run(int argc, char **argv)
{
return dhcpd_run(argv[1]);
}
/****************************************************************************
* Public Functions
****************************************************************************/
@ -1464,6 +1509,23 @@ int dhcpd_run(FAR const char *interface)
ninfo("Started\n");
/* Exit if the dhcpd is already executed */
if (g_dhcpd_daemon.ds_state == DHCPD_RUNNING)
{
return OK;
}
/* Update the pid if running in daemon mode */
g_dhcpd_daemon.ds_pid = getpid();
/* Indicate that we have started */
g_dhcpd_daemon.ds_state = DHCPD_RUNNING;
sem_post(&g_dhcpd_daemon.ds_sync);
/* Initialize everything to zero */
memset(&g_state, 0, sizeof(struct dhcpd_state_s));
@ -1471,7 +1533,7 @@ int dhcpd_run(FAR const char *interface)
/* Now loop indefinitely, reading packets from the DHCP server socket */
sockfd = -1;
for (; ; )
while (g_dhcpd_daemon.ds_state != DHCPD_STOP_REQUESTED)
{
/* Create a socket to listen for requests from DHCP clients */
@ -1493,7 +1555,7 @@ int dhcpd_run(FAR const char *interface)
/* On errors (other EINTR), close the socket and try again */
nerr("ERROR: recv failed: %d\n", errno);
if (errno != EINTR)
if (errno != EINTR && errno != EAGAIN)
{
close(sockfd);
sockfd = -1;
@ -1550,5 +1612,122 @@ int dhcpd_run(FAR const char *interface)
}
}
g_dhcpd_daemon.ds_pid = -1;
g_dhcpd_daemon.ds_state = DHCPD_STOPPED;
sem_post(&g_dhcpd_daemon.ds_sync);
return OK;
}
/****************************************************************************
* Name: dhcpd_start
*
* Description:
* Start the DHCPD daemon
*
* Returned Value:
* On success, the non-negative task ID of the DHCPDC daemon is returned;
* On failure, a negated errno value is returned.
*
****************************************************************************/
int dhcpd_start(FAR const char *interface)
{
FAR char *argv[2];
int pid;
argv[0] = (char *)interface;
argv[1] = NULL;
/* Is the DHCPD in a non-running state? */
sem_wait(&g_dhcpd_daemon.ds_lock);
if (g_dhcpd_daemon.ds_state == DHCPD_NOT_RUNNING ||
g_dhcpd_daemon.ds_state == DHCPD_STOPPED)
{
/* Start the DHCPD daemon */
g_dhcpd_daemon.ds_state = DHCPD_STARTED;
pid =
task_create("DHCPD daemon", CONFIG_NETUTILS_DHCPD_PRIORITY,
CONFIG_NETUTILS_DHCPD_STACKSIZE, dhcpd_task_run,
argv);
/* Handle failures to start the DHCPD daemon */
if (pid < 0)
{
int errval = errno;
DEBUGASSERT(errval > 0);
g_dhcpd_daemon.ds_state = DHCPD_STOPPED;
nerr("ERROR: Failed to start the DHCPD daemon\n", errval);
sem_post(&g_dhcpd_daemon.ds_lock);
return -errval;
}
/* Wait for any daemon state change */
do
{
sem_wait(&g_dhcpd_daemon.ds_sync);
}
while (g_dhcpd_daemon.ds_state == DHCPD_STARTED);
}
sem_post(&g_dhcpd_daemon.ds_lock);
return OK;
}
/****************************************************************************
* Name: dhcpd_stop
*
* Description:
* Stop the DHCPD daemon
*
* Returned Value:
* Zero on success; a negated errno value on failure. The current
* implementation only returns success.
*
****************************************************************************/
int dhcpd_stop(void)
{
int ret;
/* Is the DHCPD in a running state? */
sem_wait(&g_dhcpd_daemon.ds_lock);
if (g_dhcpd_daemon.ds_state == DHCPD_STARTED ||
g_dhcpd_daemon.ds_state == DHCPD_RUNNING)
{
/* Yes.. request that the daemon stop. */
g_dhcpd_daemon.ds_state = DHCPD_STOP_REQUESTED;
/* Wait for any daemon state change */
do
{
/* Signal the DHCPD client */
ret = kill(g_dhcpd_daemon.ds_pid,
CONFIG_NETUTILS_DHCPD_SIGWAKEUP);
if (ret < 0)
{
nerr("ERROR: kill pid %d failed: %d\n",
g_dhcpd_daemon.pid, errno);
break;
}
/* Wait for the DHCPD client to respond to the stop request */
sem_wait(&g_dhcpd_daemon.ds_sync);
}
while (g_dhcpd_daemon.ds_state == DHCPD_STOP_REQUESTED);
}
sem_post(&g_dhcpd_daemon.ds_lock);
return OK;
}