mirror of
https://git.busybox.net/udhcp
synced 2025-10-14 01:59:23 +08:00
socketpair signal handling
This commit is contained in:
4
AUTHORS
4
AUTHORS
@@ -1,9 +1,9 @@
|
||||
Moreton Bay DHCP Server
|
||||
udhcp server/client package
|
||||
-----------------------
|
||||
|
||||
Russ Dill <Russ.Dill@asu.edu>
|
||||
Matthew Ramsay <matthewr@moreton.com.au>
|
||||
Chris Trew <christ@moreton.com.au>
|
||||
Russ Dill <Russ.Dill@asu.edu>
|
||||
|
||||
Other Credits:
|
||||
--------------
|
||||
|
@@ -1,4 +1,11 @@
|
||||
0.9.8 (pending)
|
||||
+ updated client manpage (me)
|
||||
+ both client and server now use sockets for signal handling,
|
||||
hopefully, this will be the last needed change in signal
|
||||
handling, I'm fairly certain all the possible races are now
|
||||
closed. (me)
|
||||
+ The server now restarts the auto_time timer when it receives
|
||||
a SIGUSR1 (write out config file). (me)
|
||||
+ Improve signal handling (David Poole)
|
||||
+ Fix to config file parsing (Matt Kraai)
|
||||
+ Fix load lease logic (me)
|
||||
|
20
README
20
README
@@ -16,17 +16,21 @@ udhcpd /etc/udhcpd.eth1.conf
|
||||
|
||||
The udhcp server employs a number of simple config files:
|
||||
|
||||
udhcpd.leased
|
||||
udhcpd.leases
|
||||
------------
|
||||
|
||||
The udhcpd.leases behavior is designed for an embedded system. The
|
||||
file is written either every auto_time seconds, or when a SIGUSR1
|
||||
is received. When the file is written, a script can be optionally
|
||||
called to commit the file to flash. Lease times are stored in the
|
||||
file by time remaining in lease (for systems without clock that works
|
||||
when there is no power), or by the absolute time that it expires in
|
||||
seconds from epoch. In the remainig format, expired leases are stored
|
||||
as zero. The file is of the format:
|
||||
is received (the auto_time timer restarts if a SIGUSR1 is received).
|
||||
If you send a SIGTERM to udhcpd directly after a SIGUSR1, udhcpd will
|
||||
finish writing the leases file and wait for the aftermentioned script
|
||||
to be executed and finish before quiting, so you do not need to sleep
|
||||
between sending signals. When the file is written, a script can be
|
||||
optionally called to commit the file to flash. Lease times are stored
|
||||
in the file by time remaining in lease (for systems without clock
|
||||
that works when there is no power), or by the absolute time that it
|
||||
expires in seconds from epoch. In the remainig format, expired leases
|
||||
are stored as zero. The file is of the format:
|
||||
|
||||
16 byte MAC
|
||||
4 byte ip address
|
||||
@@ -147,7 +151,7 @@ udhcpc also responds to SIGUSR1 and SIGUSR2. SIGUSR1 will force a renew state,
|
||||
and SIGUSR2 will force a release of the current lease, and cause udhcpc to
|
||||
go into an inactive state (until it is killed, or receives a SIGUSR1). You do
|
||||
not need to sleep between sending signals, as signals received are processed
|
||||
in a logical order during the main loop (release, then renew, then term).
|
||||
sequencially in the order they are received.
|
||||
|
||||
|
||||
|
||||
|
47
dhcpc.c
47
dhcpc.c
@@ -52,9 +52,7 @@ static unsigned long server_addr;
|
||||
static unsigned long timeout;
|
||||
static int packet_num; /* = 0 */
|
||||
static int fd;
|
||||
static int renew_requested; /* = 0 */
|
||||
static int release_requested; /* = 0 */
|
||||
static int term_received; /* = 0 */
|
||||
static int signal_pipe[2];
|
||||
|
||||
#define LISTEN_NONE 0
|
||||
#define LISTEN_KERNEL 1
|
||||
@@ -177,10 +175,9 @@ static void exit_client(int retval)
|
||||
/* Signal handler */
|
||||
static void signal_handler(int sig)
|
||||
{
|
||||
switch (sig) {
|
||||
case SIGUSR1: renew_requested = 1; break;
|
||||
case SIGUSR2: release_requested = 1; break;
|
||||
case SIGTERM: term_received = 1; break;
|
||||
if (send(signal_pipe[1], &sig, sizeof(sig), MSG_DONTWAIT) < 0) {
|
||||
LOG(LOG_ERR, "Could not send signal: %s",
|
||||
strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -217,6 +214,8 @@ int main(int argc, char *argv[])
|
||||
struct in_addr temp_addr;
|
||||
int pid_fd;
|
||||
time_t now;
|
||||
int max_fd;
|
||||
int sig;
|
||||
|
||||
static struct option options[] = {
|
||||
{"clientid", required_argument, 0, 'c'},
|
||||
@@ -313,6 +312,7 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
|
||||
/* setup signal handlers */
|
||||
socketpair(AF_UNIX, SOCK_STREAM, 0, signal_pipe);
|
||||
signal(SIGUSR1, signal_handler);
|
||||
signal(SIGUSR2, signal_handler);
|
||||
signal(SIGTERM, signal_handler);
|
||||
@@ -338,10 +338,12 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
}
|
||||
if (fd >= 0) FD_SET(fd, &rfds);
|
||||
|
||||
FD_SET(signal_pipe[0], &rfds);
|
||||
|
||||
if (tv.tv_sec > 0) {
|
||||
DEBUG(LOG_INFO, "Waiting on select...\n");
|
||||
retval = select(fd + 1, &rfds, NULL, NULL, &tv);
|
||||
max_fd = signal_pipe[0] > fd ? signal_pipe[0] : fd;
|
||||
retval = select(max_fd + 1, &rfds, NULL, NULL, &tv);
|
||||
} else retval = 0; /* If we already timed out, fall through */
|
||||
|
||||
now = time(0);
|
||||
@@ -524,21 +526,26 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
break;
|
||||
/* case BOUND, RELEASED: - ignore all packets */
|
||||
}
|
||||
} else if (retval == -1 && errno == EINTR) {
|
||||
/* a signal was caught */
|
||||
if (release_requested) {
|
||||
perform_release();
|
||||
release_requested = 0;
|
||||
}
|
||||
} else if (retval > 0 && FD_ISSET(signal_pipe[0], &rfds)) {
|
||||
if (read(signal_pipe[0], &sig, sizeof(signal)) < 0) {
|
||||
DEBUG(LOG_ERR, "Could not read signal: %s",
|
||||
strerror(errno));
|
||||
continue; /* probably just EINTR */
|
||||
}
|
||||
if (renew_requested) {
|
||||
switch (sig) {
|
||||
case SIGUSR1:
|
||||
perform_renew();
|
||||
renew_requested = 0;
|
||||
}
|
||||
if (term_received) {
|
||||
break;
|
||||
case SIGUSR2:
|
||||
perform_release();
|
||||
break;
|
||||
case SIGTERM:
|
||||
LOG(LOG_INFO, "Received SIGTERM");
|
||||
exit_client(0);
|
||||
}
|
||||
}
|
||||
} else if (retval == -1 && errno == EINTR) {
|
||||
/* a signal was caught */
|
||||
} else {
|
||||
/* An error occured */
|
||||
DEBUG(LOG_ERR, "Error on select");
|
||||
|
54
dhcpd.c
54
dhcpd.c
@@ -1,6 +1,6 @@
|
||||
/* dhcpd.c
|
||||
*
|
||||
* Moreton Bay DHCP Server
|
||||
* udhcp Server
|
||||
* Copyright (C) 1999 Matthew Ramsay <matthewr@moreton.com.au>
|
||||
* Chris Trew <ctrew@moreton.com.au>
|
||||
*
|
||||
@@ -54,7 +54,7 @@
|
||||
/* globals */
|
||||
struct dhcpOfferedAddr *leases;
|
||||
struct server_config_t server_config;
|
||||
|
||||
static int signal_pipe[2];
|
||||
|
||||
/* Exit and cleanup */
|
||||
static void exit_server(int retval)
|
||||
@@ -65,12 +65,13 @@ static void exit_server(int retval)
|
||||
}
|
||||
|
||||
|
||||
/* SIGTERM handler */
|
||||
static void udhcpd_killed(int sig)
|
||||
/* Signal handler */
|
||||
static void signal_handler(int sig)
|
||||
{
|
||||
sig = 0;
|
||||
LOG(LOG_INFO, "Received SIGTERM");
|
||||
exit_server(0);
|
||||
if (send(signal_pipe[1], &sig, sizeof(sig), MSG_DONTWAIT) < 0) {
|
||||
LOG(LOG_ERR, "Could not send signal: %s",
|
||||
strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -92,6 +93,8 @@ int main(int argc, char *argv[])
|
||||
struct option_set *option;
|
||||
struct dhcpOfferedAddr *lease;
|
||||
int pid_fd;
|
||||
int max_sock;
|
||||
int sig;
|
||||
|
||||
OPEN_LOG("udhcpd");
|
||||
LOG(LOG_INFO, "udhcp server (v%s) started", VERSION);
|
||||
@@ -129,8 +132,9 @@ int main(int argc, char *argv[])
|
||||
#endif
|
||||
|
||||
|
||||
signal(SIGUSR1, write_leases);
|
||||
signal(SIGTERM, udhcpd_killed);
|
||||
socketpair(AF_UNIX, SOCK_STREAM, 0, signal_pipe);
|
||||
signal(SIGUSR1, signal_handler);
|
||||
signal(SIGTERM, signal_handler);
|
||||
|
||||
timeout_end = time(0) + server_config.auto_time;
|
||||
while(1) { /* loop until universe collapses */
|
||||
@@ -143,26 +147,42 @@ int main(int argc, char *argv[])
|
||||
|
||||
FD_ZERO(&rfds);
|
||||
FD_SET(server_socket, &rfds);
|
||||
FD_SET(signal_pipe[0], &rfds);
|
||||
if (server_config.auto_time) {
|
||||
tv.tv_sec = timeout_end - time(0);
|
||||
if (tv.tv_sec <= 0) {
|
||||
tv.tv_sec = server_config.auto_time;
|
||||
timeout_end = time(0) + server_config.auto_time;
|
||||
write_leases(0);
|
||||
}
|
||||
tv.tv_usec = 0;
|
||||
}
|
||||
retval = select(server_socket + 1, &rfds, NULL, NULL, server_config.auto_time ? &tv : NULL);
|
||||
if (!server_config.auto_time || tv.tv_sec > 0) {
|
||||
max_sock = server_socket > signal_pipe[0] ? server_socket : signal_pipe[0];
|
||||
retval = select(max_sock + 1, &rfds, NULL, NULL,
|
||||
server_config.auto_time ? &tv : NULL);
|
||||
} else retval = 0; /* If we already timed out, fall through */
|
||||
|
||||
if (retval == 0) {
|
||||
write_leases(0);
|
||||
write_leases();
|
||||
timeout_end = time(0) + server_config.auto_time;
|
||||
continue;
|
||||
} else if (retval < 0) {
|
||||
} else if (retval < 0 && errno != EINTR) {
|
||||
DEBUG(LOG_INFO, "error on select");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (FD_ISSET(signal_pipe[0], &rfds)) {
|
||||
if (read(signal_pipe[0], &sig, sizeof(sig)) < 0)
|
||||
continue; /* probably just EINTR */
|
||||
switch (sig) {
|
||||
case SIGUSR1:
|
||||
LOG(LOG_INFO, "Received a SIGUSR1");
|
||||
write_leases();
|
||||
/* why not just reset the timeout, eh */
|
||||
timeout_end = time(0) + server_config.auto_time;
|
||||
continue;
|
||||
case SIGTERM:
|
||||
LOG(LOG_INFO, "Received a SIGTERM");
|
||||
exit_server(0);
|
||||
}
|
||||
}
|
||||
|
||||
if ((bytes = get_packet(&packet, server_socket)) < 0) { /* this waits for a packet - idle */
|
||||
if (bytes == -1 && errno != EINTR) {
|
||||
DEBUG(LOG_INFO, "error on read, %s, reopening socket", strerror(errno));
|
||||
|
5
files.c
5
files.c
@@ -219,8 +219,7 @@ int read_config(char *file)
|
||||
}
|
||||
|
||||
|
||||
/* the dummy var is here so this can be a signal handler */
|
||||
void write_leases(int dummy)
|
||||
void write_leases(void)
|
||||
{
|
||||
FILE *fp;
|
||||
unsigned int i;
|
||||
@@ -228,8 +227,6 @@ void write_leases(int dummy)
|
||||
time_t curr = time(0);
|
||||
unsigned long lease_time;
|
||||
|
||||
dummy = 0;
|
||||
|
||||
if (!(fp = fopen(server_config.lease_file, "w"))) {
|
||||
LOG(LOG_ERR, "Unable to open %s for writing", server_config.lease_file);
|
||||
return;
|
||||
|
2
files.h
2
files.h
@@ -11,7 +11,7 @@ struct config_keyword {
|
||||
|
||||
|
||||
int read_config(char *file);
|
||||
void write_leases(int dummy);
|
||||
void write_leases(void);
|
||||
void read_leases(char *file);
|
||||
|
||||
#endif
|
||||
|
3
socket.c
3
socket.c
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* socket.c -- DHCP server client/server socket creation
|
||||
*
|
||||
* Moreton Bay DHCP Server
|
||||
* udhcp client/server
|
||||
* Copyright (C) 1999 Matthew Ramsay <matthewr@moreton.com.au>
|
||||
* Chris Trew <ctrew@moreton.com.au>
|
||||
*
|
||||
@@ -153,6 +153,5 @@ int raw_socket(int ifindex)
|
||||
}
|
||||
|
||||
return fd;
|
||||
|
||||
}
|
||||
|
||||
|
24
udhcpc.8
24
udhcpc.8
@@ -20,6 +20,10 @@ Do not fork after obtaining a lease.
|
||||
Send the client hostname
|
||||
.IR HOSTNAME .
|
||||
.TP
|
||||
.BI \-h\ HOSTNAME
|
||||
Alias for -H
|
||||
.IR HOSTNAME .
|
||||
.TP
|
||||
.BI \-i\ INTERFACE ,\ \-\-interface= INTERFACE
|
||||
Configure
|
||||
.IR INTERFACE .
|
||||
@@ -47,7 +51,7 @@ Display version.
|
||||
.SH USAGE
|
||||
When an event occurs,
|
||||
.B udhcpc
|
||||
executes a script. There are three possible arguments to this
|
||||
executes a script. There are four possible arguments to this
|
||||
script:
|
||||
.TP
|
||||
.B deconfig
|
||||
@@ -68,9 +72,22 @@ configure the interface and set any other relevant parameters
|
||||
.B renew
|
||||
.B renew
|
||||
is used when
|
||||
.B udhcpc when a lease is renewed. The interface is already
|
||||
.B udhcpc
|
||||
when a lease is renewed. The interface is already
|
||||
configured, so the IP address will not change. Other parameters
|
||||
(e.g., default gateway, subnet mask, dns server) may.
|
||||
.TP
|
||||
.B nak
|
||||
.B nak
|
||||
is used when
|
||||
.B udhcpc
|
||||
receieves a NAK packet from the server. The
|
||||
enviromental variable
|
||||
.B $message
|
||||
will contain the reason for the
|
||||
NAK message if the server included one. Processing this message
|
||||
is optional, as the script will also be called with deconfig if
|
||||
need be.
|
||||
.PP
|
||||
Parameters are passed to the script via the following environment
|
||||
variables:
|
||||
@@ -163,6 +180,9 @@ The DHCP message type (safely ignored).
|
||||
.B serverid
|
||||
The server IP address.
|
||||
.TP
|
||||
.B message
|
||||
Reason for a DHCPNAK.
|
||||
.TP
|
||||
.B tftp
|
||||
The TFTP server name.
|
||||
.TP
|
||||
|
Reference in New Issue
Block a user